﻿//Copyright (c) 2010 Christopher E. S. King (http://chriskingconsulting.com)
//
//Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files 
// (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, 
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do 
// so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE 
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Collections;
using System.Collections.Concurrent;
using System.Threading;
using System.Runtime.Remoting;
using System.Threading.Tasks;
using System.Diagnostics.Contracts;
using System.Reflection;
using System.Diagnostics;
using Roslyn.Compilers.CSharp;
using System.Text.RegularExpressions;

using King.Declarative;
using King.Text;
using King.Reflection;
using King.Extensions;
using King.Collections;
using King.Traverse;
using King.CSharp.Reflection;

namespace King.CSharp.Text2 {
#if false
    public sealed class CsTypesAttribute : Attribute {

        public CsTypesAttribute(params Type[] types) { }
    }

    [Declaration(SubstituteTypes = typeof(CSharpKeyword))]
    public sealed class CSharpSubstitute : TextDeclaration {

        protected override IEnumerable Substitute(DeclarationContext context, object value) {
            yield return value.ToString().ToLower();
        }
    }

    public sealed class CSharpCompilationUnit : TextDeclaration {

        private object m_attributes;
        private object m_usings;

        public CSharpCompilationUnit(
            object attributes = null,
            object usings = null) {

            m_attributes = attributes;
            m_usings = usings;
        }

        protected override IEnumerable Substance() {
            yield return m_attributes;
            yield return m_usings;
            yield return Children();
        }
        protected override IEnumerable Children(DeclarationContext context) {
            return new TextDoubleSpaced() {
                new CSharpUsings(m_usings),

                new TextSingleSpaced() { 
                    new CSharpAttributeGroups(m_attributes) 
                },

                Children()
            };
        }
    }

    internal sealed class CSharpUsings : LeafTextDeclaration {

        private object m_usings;

        internal CSharpUsings(object usings) {
            m_usings = usings;
        }

        protected override IEnumerable Substance() {
            yield return m_usings;
        }
        protected override IEnumerable Children(DeclarationContext context) {
            return new TextSingleSpaced() { 
                from o in context.Flatten(m_usings)
                select o is CSharpUsing ? o : new CSharpUsing(o)
            };
        }
    }

    internal sealed class CSharpAttributeGroups : LeafTextDeclaration {

        private object m_groups;

        internal CSharpAttributeGroups(object groups) {
            m_groups = groups;
        }

        protected override IEnumerable Substance() {
            yield return m_groups;
        }
        protected override IEnumerable Children(DeclarationContext context) {
            var group = default(List<object>);

            // group nodes into attribute groups
            foreach (var o in context.Flatten(m_groups)) {

                // node is not already a group so add it to the group under construction
                if (!(o is CSharpAttributeGroup)) {

                    if (group == null)
                        group = new List<object>();

                    group.Add(o);

                    // node is already a group so yield any group under construction followed by this group
                } else {

                    if (group != null)
                        yield return new CSharpAttributeGroup() { group };

                    group = null;

                    yield return o;
                }
            }

            // no more groups so yield any new group under construction
            if (group != null)
                yield return new CSharpAttributeGroup() { group };
        }
    }

    public sealed class CSharpAttributeGroup : TextDeclaration {

        private object m_target;

        public CSharpAttributeGroup(
            object target = null) {

            m_target = target;
        }

        protected override IEnumerable Substance() {
            return Children();
        }
        protected override IEnumerable Children(DeclarationContext context) {
            yield return "[";

            if (context.IsSubstantial(m_target)) {
                yield return m_target;
                yield return ": ";
            }

            yield return new TextJoin(", ") { 
                from o in context.Flatten(Children())
                select o is CSharpAttribute ? o : new CSharpAttribute(o)
            };

            yield return "]";
        }
    }

    [Declaration(IsSubstantial = true)]
    public sealed class CSharpUsing : LeafTextDeclaration {

        private object m_name;
        private object m_alias;

        public CSharpUsing(
            object name,
            object alias = null) {

            m_name = name;
            m_alias = alias;
        }

        protected override IEnumerable Children(DeclarationContext context) {
            return new TextDeclaration() { "using", ' ', m_name, ";" };
        }
    }

    [Declaration(IsSubstantial = true)]
    public sealed class CSharpAttribute : LeafTextDeclaration {

        private object m_name;
        private object m_arguments;
        private object m_namedArguments;

        public CSharpAttribute(
            object name,
            object arguments = null,
            object namedArguments = null) {

            m_name = name;
            m_arguments = arguments;
            m_namedArguments = namedArguments;
        }

        protected override IEnumerable Children(DeclarationContext context) {
            yield return m_name;

            if (m_arguments == null && m_namedArguments == null)
                yield break;

            yield return new TextJoin(", ", "(", ")") {
                m_arguments == null ? null : new TextJoin(", ") { m_arguments },
                m_namedArguments == null ? null : new TextNameValue(m_namedArguments)
            };
        }
    }

    public sealed class CSharpAttributeArgument : LeafTextDeclaration {

        public CSharpAttributeArgument(
            object name,
            object expression,
            bool namedProperty = false) {
        }
    }

    public enum CSharpKeyword {
        Using,

        Public,
        Private,
        Internal,
        Protected,

        Class,
        Struct,
        Interface,
        Enum,
        Delegate,

        Abstract,
        Static,
        Sealed,
        Partial,
        Extern,
    }

    public sealed class CSharpGenericParameterConstraint : LeafTextDeclaration {

        private object m_name;
        private object m_constraints;
        private bool m_isClassConstraint;
        private bool m_isStructConstraint;
        private bool m_isNewConstraint;

        public CSharpGenericParameterConstraint(
            object name,
            object constraints,
            bool isClassConstraint = false,
            bool isStructConstraint = false,
            bool isNewConstraint = false) {

            m_name = name;
            m_constraints = constraints;
            m_isClassConstraint = isClassConstraint;
            m_isStructConstraint = isStructConstraint;
            m_isNewConstraint = isNewConstraint;
        }

        protected override IEnumerable Substance() {
            if (m_isClassConstraint || m_isStructConstraint || m_isNewConstraint)
                yield return Substantial;
            else
                yield return m_constraints;
        }
        protected override IEnumerable Children(DeclarationContext context) {
            var prefix = new TextJoin() { "where", m_name, ": " };

            return new TextJoin(prefix: prefix) {
                m_isClassConstraint ? "class" : null,
                m_isStructConstraint ? "struct" : null,
                m_isNewConstraint ? "new()" : null,
                m_constraints,
            };
        }
    }

    public sealed class CSharpTypeSyntax : TextDeclaration {

        private object m_name;
        private object m_baseType;
        private object m_interfaces;
        private object m_constraints;

        private bool m_isPublic;
        private bool m_isPrivate;
        private bool m_isProtected;
        private bool m_isInternal;
        private bool m_isStruct;
        private bool m_isInterface;
        private bool m_isEnum;
        private bool m_isAbstract;
        private bool m_isStatic;
        private bool m_isPartial;
        private bool m_isSealed;
        private bool m_isExtern;

        private object m_attributes;

        public CSharpTypeSyntax(
            object name,
            object baseType = null,
            object interfaces = null,
            object constraints = null,
            bool isPublic = false,
            bool isPrivate = false,
            bool isProtected = false,
            bool isInternal = false,
            bool isStruct = false,
            bool isInterface = false,
            bool isEnum = false,
            bool isAbstract = false,
            bool isStatic = false,
            bool isPartial = false,
            bool isSealed = false,
            bool isExtern = false,
            object attributes = null) {

            m_name = name;
            m_baseType = baseType;
            m_interfaces = interfaces;
            m_constraints = constraints;

            m_isPublic = isPublic;
            m_isPrivate = isPrivate;
            m_isProtected = isProtected;
            m_isInternal = isInternal;

            m_isStruct = isStruct;
            m_isInterface = isInterface;
            m_isEnum = isEnum;
            m_isAbstract = isAbstract;
            m_isStatic = isStatic;
            m_isPartial = isPartial;
            m_isSealed = isSealed;
            m_isExtern = isExtern;

            m_attributes = attributes;
        }

        protected override IEnumerable Children(DeclarationContext context) {
            var modifiers = new List<object>();

            if (m_isPublic) modifiers.Add(CSharpKeyword.Public);
            if (m_isPrivate) modifiers.Add(CSharpKeyword.Private);
            if (m_isInternal) modifiers.Add(CSharpKeyword.Internal);
            if (m_isProtected) modifiers.Add(CSharpKeyword.Protected);

            if (m_isExtern) modifiers.Add(CSharpKeyword.Extern);
            if (m_isAbstract) modifiers.Add(CSharpKeyword.Abstract);
            if (m_isSealed) modifiers.Add(CSharpKeyword.Sealed);
            if (m_isStatic) modifiers.Add(CSharpKeyword.Static);
            if (m_isPartial) modifiers.Add(CSharpKeyword.Partial);

            if (m_isStruct) modifiers.Add(CSharpKeyword.Struct);
            else if (m_isInterface) modifiers.Add(CSharpKeyword.Interface);
            else if (m_isEnum) modifiers.Add(CSharpKeyword.Enum);
            else modifiers.Add(CSharpKeyword.Class);

            yield return new CSharpSubstitute() { 

                new TextSingleSpaced() {
                    new CSharpAttributeGroups(m_attributes),

                    new TextDeclaration() {
                        new TextJoin(' ') { modifiers, m_name },

                        new TextIndent {
                            new TextSingleSpaced(Environment.NewLine) { 
                                new TextJoin(", ", ": ") { m_baseType, m_interfaces },
                                m_constraints 
                            },
                        },

                        ' ', new CSharpBlock(inline: true) { Children() }
                    }
                }
            };
        }
    }

    public sealed class CSharpBlock : TextDeclaration {

        private bool m_openBraceOnNewLine;
        private bool m_inline;
        private bool m_force;

        public CSharpBlock(
            bool openBraceOnNewLine = false,
            bool inline = true,
            bool force = true) {

            m_openBraceOnNewLine = openBraceOnNewLine;
            m_inline = inline;
            m_force = force;
        }

        protected override IEnumerable Substance() {
            if (m_force)
                return Substantial;

            return Children();
        }
        protected override IEnumerable Children(DeclarationContext context) {
            var containsContent = context.IsSubstantial(Children());
            var content = new TextSingleSpaced() { Children() };
            var inline = m_inline && !context.ContainsNewLine(content);

            if (inline) {
                yield return "{" + ' ';

                if (containsContent) {
                    yield return Children();
                    yield return ' ';
                }

                yield return "}";

            } else {
                if (m_openBraceOnNewLine)
                    yield return Environment.NewLine;

                yield return "{" + Environment.NewLine;

                if (containsContent) {
                    yield return new TextIndent() { 
                        content 
                    };
                    yield return Environment.NewLine;
                }

                yield return "}";
            }
        }
    }



    public abstract class CsNode : TextDeclaration {

        //[DeclarationContainsState]
        private class CsFrame : TextDeclaration {

            private StringBuilder m_buffer;
            private List<SyntaxNodeOrToken> m_nodeOrTokens;

            internal bool OnCharacter(char character) {
                if (m_buffer == null) {

                    // initialize trivia buffer with trailing trivia of last node
                    if (m_nodeOrTokens != null) {

                        var lastNodeOrToken = m_nodeOrTokens.Last();
                        if (lastNodeOrToken.HasTrailingTrivia)
                            m_buffer = new StringBuilder(lastNodeOrToken.GetTrailingTrivia().ToString());
                    }

                    if (m_buffer == null)
                        m_buffer = new StringBuilder();
                }

                m_buffer.Append(character);
                return true;
            }
            internal void AddNodeOrToken(SyntaxNodeOrToken nodeOrToken) {
                // trivial case when there is no trivia
                if (m_buffer == null) {
                    if (m_nodeOrTokens == null)
                        m_nodeOrTokens = new List<SyntaxNodeOrToken>();
                    m_nodeOrTokens.Add(nodeOrToken);
                    return;
                }

                // if the node already has leading trivia then append it to the buffer
                if (nodeOrToken.HasLeadingTrivia)
                    m_buffer.Append(nodeOrToken.GetLeadingTrivia().ToString());

                // dump trivia so it can be re-parsed and possibly split between adjoining nodes
                var trivia = m_buffer.ToString();
                var leadingTriviaOffset = 0;

                // if this is the first node then create the list
                if (m_nodeOrTokens == null) {
                    m_nodeOrTokens = new List<SyntaxNodeOrToken>();

                    // else the node has and older sibling so split the trivia between them
                } else {
                    var trailingTriva = Syntax.ParseTrailingTrivia(trivia);
                    leadingTriviaOffset = trailingTriva.Count;

                    // replace older siblings trailing trivia with new trailing trivia
                    var olderSibling = m_nodeOrTokens.Last();
                    m_nodeOrTokens[m_nodeOrTokens.Count - 1] = olderSibling.WithTrailingTrivia(trailingTriva);
                }

                // add new node with leading trivia
                m_nodeOrTokens.Add(
                    nodeOrToken.WithLeadingTrivia(
                        Syntax.ParseLeadingTrivia(trivia, leadingTriviaOffset)));
            }
            internal List<SyntaxNodeOrToken> NodesAndTokens {
                get { return m_nodeOrTokens; }
            }
            internal string Text {
                get {
                    if (m_buffer == null)
                        return null;
                    return m_buffer.ToString();
                }
            }

            //protected override void Prolog(DeclarationContext context) {
            //    m_nodeOrTokens = null;
            //    m_buffer = null;
            //}
            //protected override void Epilog(DeclarationContext context) {
            //    if (m_buffer != null && m_nodeOrTokens == null)
            //        return;

            //    // replace last node trailing trivia with all remaining trivia
            //    if (m_buffer != null && m_nodeOrTokens != null)
            //        m_nodeOrTokens[m_nodeOrTokens.Count - 1] =
            //            m_nodeOrTokens.Last().WithLeadingTrivia(Syntax.ParseLeadingTrivia(m_buffer.ToString()));

            //    m_buffer = null;
            //}
        }

        private SyntaxNodeOrToken m_nodeOrToken;

        internal CsNode() { }

        internal SyntaxNodeOrToken NodeOrToken {
            get { return m_nodeOrToken; }
        }
        internal SyntaxNode Node {
            get { return m_nodeOrToken.AsNode(); }
        }
        internal SyntaxToken Token {
            get { return m_nodeOrToken.AsToken(); }
        }

        internal virtual IEnumerable Nodes(DeclarationContext context) {
            throw new NotImplementedException();
        }
        internal virtual SyntaxNodeOrToken Activate(SyntaxNodesOrTokens nodesOrTokens) {
            throw new NotImplementedException();
        }
        internal virtual SyntaxNodeOrToken Activate(string code) {
            throw new NotImplementedException();
        }
        internal virtual SyntaxNodeOrToken Activate() {
            return default(SyntaxNodeOrToken);
        }

        protected sealed override IEnumerable Children(DeclarationContext context) {
            // punctuation nodes simply return a token
            var nodeOrToken = Activate();

            // non-trivial nodes require evaluation
            if (nodeOrToken.Kind == SyntaxKind.None) {

                // construct the frame for this CsNode. Child CsNodes push their node or token into this frame
                var frame = new CsFrame() { Nodes(context) };

                // traverse the tree
                //context.Evaluate(frame, frame.OnCharacter);
                throw new NotSupportedException();

                // activate the node or token for this CsNode
                var nodesAndTokens = frame.NodesAndTokens;
                var text = frame.Text;

                // nodes can be created by construction (internal nodes) or by parsing (leaf nodes)
                if (nodesAndTokens != null)
                    // activate by construction
                    nodeOrToken = Activate(new SyntaxNodesOrTokens(nodesAndTokens));

                else if (text != null)
                    // activate by parsing
                    nodeOrToken = Activate(text);

                else
                    // there was no content captured by the frame
                    yield break;
            }

            // push the node or token to the parent frame (if any)
            var parent = context.Ancestors<CsFrame>().FirstOrDefault();
            if (parent != null)
                parent.AddNodeOrToken(nodeOrToken);

            // save this node or token
            m_nodeOrToken = nodeOrToken;

            // yield the node or token (a parent must substitute it for its text)
            yield return Node;
        }
    }

    public static class CsKeyword {

        static CsKeyword() {
            CsToken.LoadTokens(typeof(CsKeyword), "Keyword");
        }

        public static CsToken Class;
        public static CsToken Struct;
        public static CsToken Interface;
        public static CsToken Enum;
        public static CsToken Out;
        public static CsToken Ref;
    }
    public static class CsPunctuation {

        static CsPunctuation() {
            CsToken.LoadTokens(typeof(CsPunctuation), "Token");
        }

        public static CsToken OpenParen;
        public static CsToken CloseParen;

        public static CsToken OpenBracket;
        public static CsToken CloseBracket;

        public static CsToken OpenBrace;
        public static CsToken CloseBrace;

        public static CsToken Colon;
        public static CsToken Comma;
        public static CsToken Equals;
    }

    internal struct SyntaxNodesOrTokens : IEnumerable<SyntaxNodeOrToken> {

        private List<SyntaxNodeOrToken> m_nodesOrTokens;

        internal SyntaxNodesOrTokens(List<SyntaxNodeOrToken> nodesOrTokens) {
            m_nodesOrTokens = nodesOrTokens;
        }

        private void ThrowException(int index) {
            throw new InvalidOperationException();
        }

        private SyntaxNodeOrToken Get(ref int index, SyntaxKind? kind = null) {
            var result = TryGet(ref index, kind);
            if (result == null)
                ThrowException(index);

            var nodeOrToken = (SyntaxNodeOrToken)result;
            if (kind != null && nodeOrToken.Kind != kind) {
                index--;
                ThrowException(index);
            }

            return nodeOrToken;
        }
        private SyntaxNodeOrToken? TryGet(ref int index, SyntaxKind? kind = null) {
            if (index >= m_nodesOrTokens.Count)
                return null;

            var nodeOrToken = m_nodesOrTokens[index];
            if (kind != null && nodeOrToken.Kind != kind)
                return null;

            index++;
            return nodeOrToken;
        }

        internal SyntaxToken? TryGetToken(ref int index, SyntaxKind? kind = null) {
            var result = TryGet(ref index, kind);
            if (result == null)
                return null;

            var value = result.Value;
            if (!value.IsToken) {
                index--;
                return null;
            }

            return value.AsToken();
        }
        internal SyntaxToken GetToken(ref int index, SyntaxKind? kind = null) {
            var result = Get(ref index, kind);
            if (!result.IsToken)
                ThrowException(--index);
            return result.AsToken();
        }
        internal SyntaxToken GetKeyword(ref int index) {
            var result = Get(ref index);
            if (!result.Kind.ToString().EndsWith("Keyword"))
                ThrowException(--index);
            return (SyntaxToken)result;
        }
        internal SyntaxToken? TryGetIdentifier(ref int index) {
            return TryGetToken(ref index, SyntaxKind.IdentifierToken);
        }
        internal SyntaxToken GetEof(ref int index) {
            throw new NotImplementedException();
        }

        internal SyntaxNode TryGetNode(ref int index, SyntaxKind? kind = null) {
            var maybeResult = TryGet(ref index, kind);
            if (maybeResult == null)
                return null;

            var result = (SyntaxNodeOrToken)maybeResult;
            if (!result.IsNode) {
                index--;
                return null;
            }

            return result.AsNode();
        }
        internal SyntaxNode GetNode(ref int index, SyntaxKind? kind = null) {
            var result = Get(ref index, kind);
            if (!result.IsNode)
                ThrowException(--index);
            return result.AsNode();
        }
        internal T TryGet<T>(ref int index) where T : class {
            var result = TryGetNode(ref index);
            if (!(result is T)) {
                index--;
                return null;
            }

            return result as T;
        }
        internal T Get<T>(ref int index) where T : class {
            var result = GetNode(ref index) as T;
            if (result == null)
                ThrowException(index--);
            return result;
        }
        internal ArgumentSyntax GetArgument(ref int index) {
            return Get<ArgumentSyntax>(ref index);
        }
        internal AttributeArgumentSyntax GetAttributeArgument(ref int index) {
            var argument = TryGet<ArgumentSyntax>(ref index);
            if (argument != null)
                return Syntax.AttributeArgument(
                    nameColonOpt: argument.NameColonOpt, expression: argument.Expression);

            return Get<AttributeArgumentSyntax>(ref index);
        }
        internal ExpressionSyntax GetExpression(ref int index) {
            return Get<ExpressionSyntax>(ref index);
        }
        internal SyntaxToken GetIdentifier(ref int index) {
            return GetToken(ref index, SyntaxKind.IdentifierToken);
        }
        internal NameSyntax GetName(ref int index) {
            return Get<NameSyntax>(ref index);
        }

        internal AttributeArgumentListSyntax GetAttributeArguments(ref int index) {
            var maybeOpenParan = TryGetToken(ref index, SyntaxKind.OpenParenToken);
            if (maybeOpenParan == null)
                return null;

            var separators = new List<SyntaxToken>();
            var arguments = new List<AttributeArgumentSyntax>();

            var token = GetToken(ref index);
            while (token.Kind != SyntaxKind.CloseParenToken) {
                var argument = GetAttributeArgument(ref index);
                arguments.Add(argument);

                token = GetToken(ref index);
                if (token.Kind == SyntaxKind.CommaToken)
                    separators.Add(token);
            }

            var openParan = maybeOpenParan.Value;
            var closeParan = token;

            var separatedList = Syntax.SeparatedList(arguments, separators);
            return Syntax.AttributeArgumentList(openParan, separatedList, closeParan);
        }
        internal AttributeTargetSpecifierSyntax GetAttributeTarget(ref int index) {
            var maybeIdentifier = TryGetIdentifier(ref index);
            if (maybeIdentifier == null)
                return null;

            var identifier = (SyntaxToken)maybeIdentifier;
            var colon = GetToken(ref index, SyntaxKind.ColonToken);
            return Syntax.AttributeTargetSpecifier(identifier, colon);
        }
        internal SeparatedSyntaxList<AttributeSyntax> GetAttributes(ref int index) {
            var separators = new List<SyntaxToken>();
            var arguments = new List<AttributeSyntax>();

            while (true) {
                var argument = Get<AttributeSyntax>(ref index);
                arguments.Add(argument);

                var token = TryGetToken(ref index, SyntaxKind.CommaToken);
                if (token == null)
                    break;

                separators.Add((SyntaxToken)token);
            }

            var separatedList = Syntax.SeparatedList(arguments, separators);
            return separatedList;
        }
        internal SyntaxList<AttributeDeclarationSyntax> GetAttributeGroups(ref int index) {
            throw new NotImplementedException();
        }

        internal object GetMembers(ref int index) {
            throw new NotImplementedException();
        }
        internal SyntaxList<TypeParameterConstraintClauseSyntax> GetConstraints(ref int index) {
            throw new NotImplementedException();
        }
        internal BaseListSyntax GetBaseTypeAndInterfaces(ref int index) {
            throw new NotImplementedException();
        }
        internal TypeParameterListSyntax GetTypeParameters(ref int index) {
            throw new NotImplementedException();
        }
        internal SyntaxTokenList GetModifiers(ref int index) {
            throw new NotImplementedException();
        }

        public IEnumerator<SyntaxNodeOrToken> GetEnumerator() {
            return m_nodesOrTokens.GetEnumerator();
        }
        IEnumerator IEnumerable.GetEnumerator() {
            return GetEnumerator();
        }
    }

    internal sealed class CsAttributeGroups : LeafTextDeclaration {

        private object m_groups;

        internal CsAttributeGroups(object groups) {
            m_groups = groups;
        }

        protected override IEnumerable Substance() {
            yield return m_groups;
        }
        protected override IEnumerable Children(DeclarationContext context) {
            var group = default(List<object>);

            // group nodes into attribute groups
            foreach (var o in context.Flatten(m_groups)) {

                // node is not already a group so add it to the group under construction
                if (!(o is CSharpAttributeGroup)) {

                    if (group == null)
                        group = new List<object>();

                    group.Add(o);

                    // node is already a group so yield any group under construction followed by this group
                } else {

                    if (group != null)
                        yield return new CSharpAttributeGroup() { group };

                    group = null;

                    yield return o;
                }
            }

            // no more groups so yield any new group under construction
            if (group != null)
                yield return new CSharpAttributeGroup() { group };
        }
    }

    public sealed class CsAttributeGroup : CsNode {

        private object m_target;

        public CsAttributeGroup(
            object target = null) {

            m_target = target;
        }

        protected override IEnumerable Substance() {
            return Children();
        }

        internal override IEnumerable Nodes(DeclarationContext context) {
            yield return CsPunctuation.OpenBracket;

            if (context.IsSubstantial(m_target)) {
                yield return new CsIdentifier(m_target);
                yield return CsPunctuation.Colon;
                yield return ' ';
            }

            var commaSpace = new object[] { CsPunctuation.Comma, ' ' };

            yield return new TextJoin(commaSpace) { 
                context.Flatten(Children())
                    .Select(o => o is CsAttribute ? o : new CsAttribute(o))
            };

            yield return CsPunctuation.CloseBracket;
        }
        internal override SyntaxNodeOrToken Activate(SyntaxNodesOrTokens nodesOrTokens) {
            var index = 0;
            var openBracket = nodesOrTokens.GetToken(ref index, SyntaxKind.OpenBracketToken);
            var target = nodesOrTokens.GetAttributeTarget(ref index);
            var attributes = nodesOrTokens.GetAttributes(ref index);
            var closeBracket = nodesOrTokens.GetToken(ref index, SyntaxKind.CloseBracketToken);

            return Syntax.AttributeDeclaration(openBracket, target, attributes, closeBracket);
        }
    }

    public sealed class CsArgument : CsNode {

        private object m_argument;
        private object m_name;
        private bool m_isNamedMember, m_isRef, m_isOut;

        public CsArgument(object argument) {
            m_argument = argument;
        }
        public CsArgument(object name, object argument, bool isNamedMember = false, bool isRef = false, bool isOut = false) {
            m_name = name;
            m_argument = argument;
            m_isNamedMember = isNamedMember;
            m_isRef = isRef;
            m_isOut = isOut;
        }

        protected override IEnumerable Substance() {
            yield return m_argument;
        }

        internal override IEnumerable Nodes(DeclarationContext context) {
            if (m_name == null) {
                yield return m_argument;

            } else {
                yield return new CsIdentifier(m_name);

                if (m_isNamedMember)
                    yield return new object[] { ' ', CsPunctuation.Equals };
                else
                    yield return CsPunctuation.Colon;

                if (m_isOut)
                    yield return new object[] { ' ', CsKeyword.Out };
                else if (m_isRef)
                    yield return new object[] { ' ', CsKeyword.Ref };

                yield return ' ';

                yield return new CsExpression(m_argument);
            }
        }
        internal override SyntaxNodeOrToken Activate(string code) {
            return Syntax.ParseArgumentList(code).ChildNodes().First();
        }
        internal override SyntaxNodeOrToken Activate(SyntaxNodesOrTokens nodesOrTokens) {
            var index = 0;

            var nameColon = default(NameColonSyntax);

            var maybeIdentifier = nodesOrTokens.TryGetIdentifier(ref index);
            var expression = nodesOrTokens.GetExpression(ref index);

            if (maybeIdentifier != null) {
                var identifier = (SyntaxToken)maybeIdentifier;

                var separator = nodesOrTokens.GetToken(ref index);
                if (separator.Kind == SyntaxKind.EqualsToken)
                    return Syntax.AttributeArgument(
                        nameEqualsOpt: Syntax.NameEquals(identifier, separator), expression: expression);

                nameColon = Syntax.NameColon(identifier, separator);
            }

            var maybeRefOrOutKeyword = nodesOrTokens.TryGetToken(ref index);

            // if this argument is used in a custom attribute it will be transformed into a AttributeArgument
            return Syntax.Argument(nameColon, (SyntaxToken)maybeRefOrOutKeyword, expression);
        }
    }

    public sealed class CsExpression : CsNode {

        private object m_expression;

        public CsExpression(object expression) {
            m_expression = expression;
        }

        internal override IEnumerable Nodes(DeclarationContext context) {
            yield return m_expression;
        }
        internal override SyntaxNodeOrToken Activate(string code) {
            return Syntax.ParseExpression(code);
        }
    }

    [Declaration(IsSubstantial = true)]
    public sealed class CsAttribute : CsNode {

        private object m_name;
        private object m_arguments;
        private object m_namedArguments;

        public CsAttribute(
            object name,
            object arguments = null,
            object namedArguments = null) {

            m_name = name;
            m_arguments = arguments;
            m_namedArguments = namedArguments;
        }

        internal override IEnumerable Nodes(DeclarationContext context) {
            yield return new CsName(m_name);

            if (m_arguments == null && m_namedArguments == null)
                yield break;

            var commaSpace = new object[] { CsPunctuation.Comma, ' ' };

            yield return new TextJoin(commaSpace, CsPunctuation.OpenParen, CsPunctuation.CloseParen) {
                m_arguments == null ? null : new TextJoin(commaSpace) { m_arguments },
                m_namedArguments == null ? null : new TextNameValue(m_namedArguments)
            };
        }
        internal override SyntaxNodeOrToken Activate(SyntaxNodesOrTokens nodesOrTokens) {
            int index = 0;

            return Syntax.Attribute(
                nodesOrTokens.GetName(ref index),
                nodesOrTokens.GetAttributeArguments(ref index)
            );
        }
    }

    [Declaration(IsSubstantial = true)]
    public sealed class CsToken : CsNode {

        internal static void LoadTokens(Type type, string suffix) {
            var fieldsAndKeywords =
                from field in type.GetFields()
                join keyword in typeof(SyntaxKind).GetFields()
                    on field.Name + suffix equals keyword.Name
                select new {
                    Field = field,
                    Keyword = keyword
                };

            foreach (var o in fieldsAndKeywords)
                o.Field.SetValue(value: new CsToken(Syntax.Token((SyntaxKind)o.Keyword.GetValue())));
        }

        private SyntaxToken m_token;

        internal CsToken(SyntaxToken token) {
            m_token = token;
        }

        internal SyntaxToken SyntaxToken {
            get { return m_token; }
        }

        internal override SyntaxNodeOrToken Activate() {
            return m_token;
        }

        public string FullText {
            get { return m_token.GetFullText(); }
        }
        public string Text {
            get { return m_token.GetText(); }
        }

        public override string ToString() {
            return m_token.GetFullText();
        }
    }

    public sealed class CsModifiers : CsNode {

        public CsModifiers(
            bool isPublic = false,
            bool isPrivate = false,
            bool isProtected = false,
            bool isInternal = false,

            bool isStruct = false,
            bool isInterface = false,
            bool isEnum = false,

            bool isAbstract = false,
            bool isStatic = false,
            bool isPartial = false,
            bool isSealed = false,
            bool isExtern = false) {
        }

        internal override IEnumerable Nodes(DeclarationContext context) {
            throw new NotImplementedException();
        }
        internal override SyntaxNodeOrToken Activate(SyntaxNodesOrTokens nodesOrTokens) {
            throw new NotImplementedException();
        }
    }

    [Declaration(IsSubstantial = true)]
    public sealed class CsTypeDefinition : CsNode {

        private class Info {
            internal object Identifier;
            internal object TypeParameters;
            internal object Modifiers;
            internal object Attributes;

            internal bool IsStruct;
            internal bool IsInterface;
            internal bool IsEnum;

            internal object BaseTypesAndInterfaces;
            internal object ConstraintClauses;
        }

        private Info m_info;

        public CsTypeDefinition(
            object identifier,
            object typeParameters = null,
            object modifiers = null,
            object attributes = null,

            bool isStruct = false,
            bool isInterface = false,
            bool isEnum = false,

            object baseTypesAndInterfaces = null,
            object constraintClauses = null) {

            m_info = new Info {
                Identifier = identifier,
                TypeParameters = typeParameters,
                Modifiers = modifiers,
                Attributes = attributes,

                IsStruct = isStruct,
                IsInterface = isInterface,
                IsEnum = isEnum,

                BaseTypesAndInterfaces = baseTypesAndInterfaces,
                ConstraintClauses = constraintClauses
            };
        }

        private ClassDeclarationSyntax ClassDeclarationSyntax {
            get { return Node as ClassDeclarationSyntax; }
        }
        private StructDeclarationSyntax StructDeclarationSyntax {
            get { return Node as StructDeclarationSyntax; }
        }
        private InterfaceDeclarationSyntax InterfaceDeclarationSyntax {
            get { return Node as InterfaceDeclarationSyntax; }
        }
        private EnumDeclarationSyntax EnumDeclarationSyntax {
            get { return Node as EnumDeclarationSyntax; }
        }

        internal override IEnumerable Nodes(DeclarationContext context) {

            var keyword = CsKeyword.Class;
            if (m_info.IsStruct)
                keyword = CsKeyword.Struct;
            else if (m_info.IsInterface)
                keyword = CsKeyword.Interface;
            else if (m_info.IsEnum)
                keyword = CsKeyword.Enum;

            yield return new TextSingleSpaced() {
                new CsAttributeGroups(m_info.Attributes),

                new TextDeclaration() {
                    new TextJoin(' ') { m_info.Attributes, keyword, new CsIdentifier(m_info.Identifier) },

                    new TextIndent {
                        new TextSingleSpaced(Environment.NewLine) { 
                            new TextJoin(", ", ": ") { m_info.BaseTypesAndInterfaces },
                            m_info.ConstraintClauses 
                        },
                    },

                    ' ', new CsBlock(inline: true) { Children() }
                }
            };
        }
        internal override SyntaxNodeOrToken Activate(SyntaxNodesOrTokens nodesOrTokens) {

            var index = 0;

            //var attributes = nodesOrTokens.GetAttributes(ref index);
            //var modifiers = nodesOrTokens.GetModifiers(ref index);
            var keyword = nodesOrTokens.GetKeyword(ref index);
            var identifier = nodesOrTokens.GetIdentifier(ref index);
            //var typeParameters = nodesOrTokens.GetTypeParameters(ref index);
            //var baseTypeAndInterfaces = nodesOrTokens.GetBaseTypeAndInterfaces(ref index);
            //var constraints = nodesOrTokens.GetConstraints(ref index);
            var token = nodesOrTokens.GetToken(ref index);

            var openBrace = default(SyntaxToken);
            var members = default(object);
            var closeBrace = default(SyntaxToken);
            var semicolon = default(SyntaxToken);

            if (token.Kind == SyntaxKind.OpenBraceToken) {
                openBrace = token;
                members = nodesOrTokens.GetMembers(ref index);
                closeBrace = nodesOrTokens.GetToken(ref index);
            } else {
                semicolon = token;
            }

            var eof = nodesOrTokens.GetEof(ref index);

            //if (keyword.Kind == SyntaxKind.ClassKeyword)
            //    return Syntax.ClassDeclaration(attributes, modifiers, keyword, identifier, typeParameters,
            //        baseTypeAndInterfaces, constraints, openBrace, (SyntaxList<MemberDeclarationSyntax>)members, closeBrace, semicolon);

            //if (keyword.Kind == SyntaxKind.InterfaceKeyword)
            //    return Syntax.InterfaceDeclaration(attributes, modifiers, keyword, identifier, typeParameters,
            //        baseTypeAndInterfaces, constraints, openBrace, (SyntaxList<MemberDeclarationSyntax>)members, closeBrace, semicolon);

            //if (keyword.Kind == SyntaxKind.StructKeyword)
            //    return Syntax.StructDeclaration(attributes, modifiers, keyword, identifier, typeParameters,
            //        baseTypeAndInterfaces, constraints, openBrace, (SyntaxList<MemberDeclarationSyntax>)members, closeBrace, semicolon);

            //if (keyword.Kind == SyntaxKind.EnumKeyword)
            //    return Syntax.EnumDeclaration(attributes, modifiers, keyword, identifier,
            //        baseTypeAndInterfaces, openBrace, (SeparatedSyntaxList<EnumMemberDeclarationSyntax>)members, closeBrace, semicolon);

            throw new NotSupportedException();
        }
    }

    public sealed class CsCompilationUnit : CsNode {

        private object m_attributes;
        private object m_usings;

        public CsCompilationUnit(
            object attributes = null,
            object usings = null) {

            m_attributes = attributes;
            m_usings = usings;
        }

        protected override IEnumerable Substance() {
            yield return m_attributes;
            yield return m_usings;
            yield return Children();
        }

        internal override IEnumerable Nodes(DeclarationContext context) {
            return new TextDoubleSpaced() {
                new CSharpUsings(m_usings),

                new TextSingleSpaced() { 
                    new CSharpAttributeGroups(m_attributes) 
                },

                Children()
            };
        }
        internal override SyntaxNodeOrToken Activate(SyntaxNodesOrTokens nodesOrTokens) {
            throw new NotImplementedException();
        }
    }

    public sealed class CsBlock : TextDeclaration {

        private bool m_openBraceOnNewLine;
        private bool m_inline;
        private bool m_force;

        public CsBlock(
            bool openBraceOnNewLine = false,
            bool inline = true,
            bool force = true) {

            m_openBraceOnNewLine = openBraceOnNewLine;
            m_inline = inline;
            m_force = force;
        }

        protected override IEnumerable Substance() {
            if (m_force)
                return Substantial;

            return Children();
        }
        protected override IEnumerable Children(DeclarationContext context) {
            var containsContent = context.IsSubstantial(Children());
            var content = new TextSingleSpaced() { Children() };
            var inline = m_inline && !context.ContainsNewLine(content);

            if (inline) {
                yield return CsPunctuation.OpenBrace;
                yield return ' ';

                if (containsContent) {
                    yield return Children();
                    yield return ' ';
                }

                yield return CsPunctuation.CloseBrace;

            } else {
                if (m_openBraceOnNewLine)
                    yield return Environment.NewLine;

                yield return CsPunctuation.OpenBrace;
                yield return Environment.NewLine;

                if (containsContent) {
                    yield return new TextIndent() { 
                        content 
                    };
                    yield return Environment.NewLine;
                }

                yield return CsPunctuation.CloseBrace;
            }
        }
    }

    [Declaration(IsSubstantial = true)]
    internal sealed class CsIdentifier : CsNode {

        private object m_identifier;

        internal CsIdentifier(object identifier) {
            m_identifier = identifier;
        }

        internal override IEnumerable Nodes(DeclarationContext context) {
            yield return m_identifier;
        }
        internal override SyntaxNodeOrToken Activate(string text) {
            return Syntax.Identifier(text);
        }
    }

    [Declaration(IsSubstantial = true)]
    internal sealed class CsName : CsNode {

        private object m_name;

        public CsName(object name) {
            m_name = name;
        }

        internal override IEnumerable Nodes(DeclarationContext context) {
            yield return m_name;
        }
        internal override SyntaxNodeOrToken Activate(string text) {
            return Syntax.ParseName(text);
        }
    }
#endif
}

namespace King.CSharp.Text {

    [DebuggerDisplay(@"\{HasTriva = {m_hasTrivia} Triva = {m_stringBuilder}}")]
    internal class Local : ICloneable {
        private char? m_character;
        private StringBuilder m_stringBuilder;
        private bool m_hasTrivia;

        internal int Count {
            get { return m_stringBuilder == null ? 0 : m_stringBuilder.Length; }
        }
        internal void Add(char character) {
            // optimize single character case
            if (m_character == null)
                m_character = character;

            // general StringBuilder case
            else {

                // allocate StringBuilder
                if (m_stringBuilder == null)
                    m_stringBuilder = new StringBuilder();

                // unoptimize single character case
                if (m_stringBuilder.Length == 0)
                    m_stringBuilder.Append(m_character);

                // appened new character
                m_stringBuilder.Append(character);
            }

            m_hasTrivia = true;
        }
        internal bool HasTrivia {
            get { return m_hasTrivia; }
        }
        internal string GetString() {
            string result = null;

            // optimize single character case
            if (m_stringBuilder == null || m_stringBuilder.Length == 0)
                result = m_character == null ? null : m_character.ToString();

            // general case
            else
                result = m_stringBuilder.ToString();

            // clear
            m_character = null;
            if (m_stringBuilder != null)
                m_stringBuilder.Clear();
            m_hasTrivia = false;

            return result;
        }

        public object Clone() {
            return new Local() {
                m_character = m_character,

                m_stringBuilder = m_stringBuilder == null ? null :
                    new StringBuilder(m_stringBuilder.ToString()),

                m_hasTrivia = m_hasTrivia
            };
        }
    }

    [Declaration(
        SubstituteTypes = new[] { typeof(CSharpObject), typeof(CSharpLeaf) },
        SubstituteCharacters = DeclarationAttribute.AllCharacters,
        UseDedicatedStack = true
    )] 
    internal class CSharpShiftReduce : Declaration {

        internal class Local : ICloneable {

            private enum BufferType {
                LeadingTrivia,
                Text,
                TrailingTrivia,
            }

            private Stack<SyntaxNodeOrToken> m_stack;
            private StringBuilder m_text;
            private StringBuilder m_leadingTrivia;
            private StringBuilder m_trailingTrivia;
            private Queue<CSharpObject> m_reductionRules;
            private BufferType m_bufferType;
            private Stack<SyntaxNodeOrToken> m_arguments;
            private SyntaxBinder m_syntaxBinder;
            private int m_expressionDepth;

            internal Local() {
                m_stack = new Stack<SyntaxNodeOrToken>();
                m_leadingTrivia = new StringBuilder();
                m_text = new StringBuilder();
                m_trailingTrivia = new StringBuilder();
                m_arguments = new Stack<SyntaxNodeOrToken>();
                m_reductionRules = new Queue<CSharpObject>();
                m_syntaxBinder = new SyntaxBinder(m_leadingTrivia);
            }

            private bool HasArguments {
                get { return m_stack.Peek().Kind != SyntaxKind.None; }
            }
            private SyntaxNodeOrToken ReduceTrivia(SyntaxNodeOrToken nodeOrToken) {

                // bail if no trivia
                if (m_leadingTrivia.IsEmpty() && m_trailingTrivia.IsEmpty())
                    return nodeOrToken;

                // node or token should not have any trivia before adding it here
                Contract.Assert(!nodeOrToken.HasLeadingTrivia);
                Contract.Assert(!nodeOrToken.HasTrailingTrivia);

                // parse trivia
                var leadingTrivia = Syntax.ParseLeadingTrivia(m_leadingTrivia.ToString());
                var trailingTrivia = Syntax.ParseTrailingTrivia(m_trailingTrivia.ToString());

                // assert all triva is consumed before and clearing
                Contract.Assert(leadingTrivia.Sum(o => o.FullSpan.Length) == m_leadingTrivia.Length);
                Contract.Assert(trailingTrivia.Sum(o => o.FullSpan.Length) == m_trailingTrivia.Length);
                m_leadingTrivia.Clear();
                m_trailingTrivia.Clear();

                // append and prepend trivia 
                nodeOrToken = nodeOrToken.WithLeadingTrivia(leadingTrivia);
                nodeOrToken = nodeOrToken.WithTrailingTrivia(trailingTrivia);

                return nodeOrToken;
            }
            private void Reduce() {

                #region Contracts
                Contract.Ensures(m_text.IsEmpty());
                Contract.Ensures(m_leadingTrivia.IsEmpty());
                Contract.Ensures(m_trailingTrivia.IsEmpty());
                Contract.Ensures(m_arguments.Count == 0);
                Contract.Ensures(m_reductionRules.Count == 0);
                Contract.Ensures(m_bufferType == BufferType.LeadingTrivia);
                Contract.Ensures(m_stack.Count < Contract.OldValue(m_stack.Count));
                #endregion

                while (m_reductionRules.Count > 0) {

                    // get deferred reduction rule
                    var reductionRule = m_reductionRules.Dequeue();

                    // shift terminals (tokens) and non-terminals (nodes) off of
                    // the main stack and onto an argument stack until the slot
                    // "reserved" for the result is encountered.
                    while (HasArguments)
                        m_arguments.Push(m_stack.Pop());
                    m_stack.Pop(); // pop the reserved slot

                    SyntaxNodeOrToken reduction;

                    // rule shifted nodes and tokens
                    if (m_text.IsEmpty()) {

                        // reduce!
                        m_syntaxBinder.Initialize(m_arguments.GetEnumerator());
                        reduction = reductionRule.Reduce(m_syntaxBinder);
                        m_arguments.Clear();

                        // if the reduction is a node then text and trailing trivia must be empty. They should
                        // have been prepended or appeneded to a token or parsed into a token
                        Contract.Assert(!reduction.IsNode || (m_trailingTrivia.IsEmpty() && m_text.IsEmpty()));
                    }

                    // rule shifted only text
                    else {

                        // parse! and move any trivia to leading and trailing trivia buffers
                        reduction = reductionRule.Parse(m_text.ToString());

                        m_text.Clear();

                        // normalize leading trivia (e.g. indention)
                        if (reduction.HasLeadingTrivia) {
                            var leadingTrivia = reduction.GetLeadingTrivia().StringJoin();
                            m_leadingTrivia.Append(leadingTrivia);
                            reduction = reduction.WithLeadingTrivia();
                        }

                        // normalize trailing trivia (e.g. whitespace follows text)
                        if (reduction.HasTrailingTrivia) {
                            var trailingTrivia = reduction.GetTrailingTrivia().StringJoin();
                            m_trailingTrivia = new StringBuilder(trailingTrivia + m_trailingTrivia);
                            reduction = reduction.WithTrailingTrivia();
                        }
                    }

                    // some productions are allowed to be vacuous (e.g. empty attribute argument)
                    if (reduction != null) {

                        // append and prepend trivia if any
                        reduction = ReduceTrivia(reduction);

                        // reset state to being buffering leading trivia
                        m_bufferType = BufferType.LeadingTrivia;

                        // shift the reduction back onto the main stack
                        m_stack.Push(reduction);
                    }
                }
            }
            private void ShiftTerminal(char character) {
                
                // leading trivia
                if (m_bufferType == BufferType.LeadingTrivia) {
                    // shift trivia or text
                    m_leadingTrivia.Append(character);
                }

                // text
                else if (m_bufferType == BufferType.Text) {
                    m_text.Append(character);
                }

                // trailing trivia
                else {

                    // \r is end of line if next character is not \n
                    if (!m_trailingTrivia.IsEmpty() && 
                        m_trailingTrivia[0] == '\r' && 
                        character != '\n') {
                        
                        // '\r' end of line encountered
                        Reduce();

                        // after reduction character is leading trivia or text
                        m_leadingTrivia.Append(character);
                        return;
                    }

                    // \n is always end of line
                    if (character == '\n') {

                        // '\n' end of line encountered
                        m_trailingTrivia.Append(character);
                        Reduce();
                        return;
                    }

                    // shift trailing trivia
                    m_trailingTrivia.Append(character);
                }
            }
            private void ShiftNonTerminal(object rule) {

                // reduce previous rule before moving onto this one
                if (m_reductionRules.Count > 0)
                    Reduce();

                // start new text buffering by converting existing text to leading trivia
                if (m_bufferType == BufferType.Text) {
                    m_leadingTrivia.Append(m_text);
                    m_text.Clear();
                }

                // a pre-parsed rule indicating where its content (first child node or token)
                // would have been were it to return content. No need to reserve a spot 
                // because the rule is pre-parsed and will return the pre-parsed node when reduced.
                if (rule is CSharpLeaf)
                    return;

                // start buffering text for this node or token
                m_bufferType = BufferType.Text;

                // "reserve" a spot on the stack for the reduction result
                m_stack.Push(default(SyntaxNodeOrToken));
            }

            internal void Shift(Value value) {
                if (value.IsCharacter)
                    // shift leading trivia
                    ShiftTerminal((char)value.Character);

                else
                    // "reserve" a spot on the stack for the reduction result
                    ShiftNonTerminal(value.Object);
            }
            internal void Reduce(CSharpObject rule) {
                // defer reduction until end of line or another node or token is encountered
                m_reductionRules.Enqueue(rule);

                // stop buffering leading trivia or text and start buffering trailing trivia
                m_bufferType = BufferType.TrailingTrivia;

                // node is not parsing text as one or more tokens or nodes 
                // has been pushed onto the stack for use during reduction
                if (HasArguments) {
                    m_trailingTrivia.Append(m_text);
                    m_text.Clear();
                }
            }
            internal SyntaxNodeOrToken Accept() {
                Reduce();

                // if the production is vacuous there is no result
                // e.g. new CSharpAttributeArgument();
                return m_stack.SingleOrDefault();
            }
            internal int ExpressionDepth {
                get { return m_expressionDepth; }
                set { m_expressionDepth = value; }
            }

            public object Clone() {
                throw new NotImplementedException();
            }
        }

        internal CSharpShiftReduce() {
        }

        private IEnumerable Shift(DeclarationContext frame, Value value) {
            // get or activiate local
            var local = (Local)frame.Local;
            if (local == null)
                frame.Local = local = new Local();

            // push expression root
            if (value.IsReference && value.Object is CSharpExpressionSyntax)
                local.ExpressionDepth++;

            // shift value
            local.Shift(value);

            // buffer characters...
            if (value.IsCharacter)
                return Declaration.Vanish;

            // ...and allow everything else to return their children 
            // which will then be shifted and finally reduced by this rule
            return null;
        }
        internal void Reduce(DeclarationContext frame, CSharpObject rule) {

            // the rule has shifted all its children and is ready to reduce them
            var local = (Local)frame.Local;
            local.Reduce(rule);

            if (rule is CSharpExpressionSyntax)
                local.ExpressionDepth--;
        }

        protected override IEnumerable Substitute(DeclarationContext frame, Value target) {
            return Shift(frame, target);
        }
        protected override IEnumerable Children(DeclarationContext frame) {

            // continue with children and buffer the result in the local
            var any = frame.Continue(Children()).Any();
            Contract.Assert(!any);

            // nothing captured
            var local = (Local)frame.Local;
            if (local == null)
                yield break;

            // accept!
            var result = local.Accept();

            // vacuous production
            if (result.Kind == SyntaxKind.None)
                yield break;

            // yield ast
            if (result.IsNode)
                yield return result.AsNode();
            else
                yield return result.AsToken();
        }
    }

    internal class SyntaxBinder {

        static SyntaxBinder() {
            ModifierKinds = new[] {
                SyntaxKind.PartialKeyword,

                SyntaxKind.StaticKeyword,
                SyntaxKind.ConstKeyword,
                SyntaxKind.ReadOnlyKeyword,

                SyntaxKind.OperatorKeyword,
                SyntaxKind.ImplicitKeyword,
                SyntaxKind.ExplicitKeyword,

                SyntaxKind.AbstractKeyword,
                SyntaxKind.VirtualKeyword,
                SyntaxKind.OverrideKeyword,
                SyntaxKind.SealedKeyword,
                SyntaxKind.NewKeyword,

                SyntaxKind.PublicKeyword,
                SyntaxKind.ProtectedKeyword,
                SyntaxKind.InternalKeyword,
                SyntaxKind.PrivateKeyword,

                SyntaxKind.PartialKeyword,
                SyntaxKind.ExternKeyword,
            }.ToHashSet();
        }

        private static readonly HashSet<SyntaxKind> ModifierKinds;

        private StringBuilder m_leadingTrivia;
        private object m_current;
        private IEnumerator m_nodesAndTokens;

        internal SyntaxBinder(StringBuilder leadingTrivia) {
            m_leadingTrivia = leadingTrivia;
        }
        internal void Initialize(IEnumerator nodesAndTokens) {
            m_nodesAndTokens = nodesAndTokens;
            m_current = null;
        }
        internal void Clear() {
            Contract.Assert(!m_nodesAndTokens.MoveNext());
            m_current = null;
            m_nodesAndTokens = null;
        }

        private bool NextNodeOrToken(out SyntaxNodeOrToken nodeOrToken) {
            nodeOrToken = default(SyntaxNodeOrToken);

            // return lookahead
            if (m_current != null && m_current is SyntaxNodeOrToken) {
                nodeOrToken = (SyntaxNodeOrToken)m_current;
                m_current = null;
                return true;
            }

            // return next
            else if (!m_nodesAndTokens.MoveNext())
                return false;

            // promise 
            if (!(m_nodesAndTokens.Current is SyntaxNodeOrToken)) {
                m_current = m_nodesAndTokens.Current;
                return false;
            }

            // node or token
            nodeOrToken = (SyntaxNodeOrToken)m_nodesAndTokens.Current;
            return true;
        }

        #region Private Members
        // tokens
        private IEnumerable<SyntaxToken> Tokens(IEnumerable<SyntaxKind> kinds) {
            SyntaxNodeOrToken nodeOrToken;
            while (NextNodeOrToken(out nodeOrToken)) {

                if (!nodeOrToken.IsToken ||
                    (kinds.Any() && !kinds.Contains(nodeOrToken.Kind))) {

                    m_current = nodeOrToken;
                    break;
                }

                yield return (SyntaxToken)nodeOrToken;
            }
        }
        private IEnumerable<SyntaxToken> Tokens(params SyntaxKind[] kinds) {
            return Tokens((IEnumerable<SyntaxKind>)kinds);
        }

        // token lists
        private SyntaxTokenList TokenList(IEnumerable<SyntaxKind> kinds) {
            return Syntax.TokenList(Tokens(kinds));
        }
        private SyntaxTokenList TokenList(params SyntaxKind[] kinds) {
            return TokenList((IEnumerable<SyntaxKind>)kinds);
        }

        // token
        private SyntaxToken TryGetToken(params SyntaxKind[] kinds) {
            return Tokens(kinds).FirstOrDefault();
        }
        private SyntaxToken GetToken(params SyntaxKind[] kinds) {
            return Tokens(kinds).First();
        }
        private SyntaxToken TryGetKeyword() {
            var result = TryGetToken();
            Contract.Assert(result.Kind == SyntaxKind.None ||
                result.Kind.ToString().EndsWith("Keyword"));
            return result;
        }
        private SyntaxToken GetKeyword() {
            var result = GetToken();
            Contract.Assert(result.Kind.ToString().EndsWith("Keyword"));
            return result;
        }
        private SyntaxToken TryGetIdentifier() {
            return TryGetToken(SyntaxKind.IdentifierToken);
        }
        private SyntaxToken GetIdentifier() {
            return GetToken(SyntaxKind.IdentifierToken);
        }
        private SyntaxToken GetEndOfFile() {
            var leadingTrivia = Syntax.ParseLeadingTrivia(m_leadingTrivia.ToString());
            m_leadingTrivia.Clear();
            return Syntax.Token(leadingTrivia, SyntaxKind.EndOfFileToken);
        }

        // tokens
        internal SyntaxTokenList Modifiers() {
            return TokenList(ModifierKinds);
        }

        // nodes
        private IEnumerable<SyntaxNode> Nodes(IEnumerable<Type> kinds) {
            SyntaxNodeOrToken nodeOrToken;
            while (NextNodeOrToken(out nodeOrToken)) {

                if (!nodeOrToken.IsNode ||
                    (kinds.Any() && !kinds.Any(o =>
                        o.IsAssignableFrom(nodeOrToken.AsNode())))) {

                    m_current = nodeOrToken;
                    break;
                }

                yield return (SyntaxNode)nodeOrToken;
            }
        }
        private IEnumerable<SyntaxNode> Nodes(params Type[] kinds) {
            return Nodes((IEnumerable<Type>)kinds);
        }
        private T GetNode<T>() where T : SyntaxNode {
            return (T)Nodes(typeof(T)).First();
        }
        private T TryGetNode<T>() where T : SyntaxNode {
            return (T)Nodes(typeof(T)).FirstOrDefault();
        }
        private NameSyntax GetName() {
            return GetNode<NameSyntax>();
        }
        private NameSyntax TryGetName() {
            return TryGetNode<NameSyntax>();
        }
        private IdentifierNameSyntax TryGetIdentifierName() {
            throw new NotImplementedException();
        }
        private IdentifierNameSyntax GetIdentifierName() {
            throw new NotImplementedException();
        }

        // node
        private new TypeSyntax GetType() {
            return GetNode<TypeSyntax>();
        }
        private TypeSyntax TryGetType() {
            return TryGetNode<TypeSyntax>();
        }
        private TypeParameterConstraintSyntax TryGetTypeParameterConstraint() {

            // class or struct constraint
            var classOrStruct = TryGetToken(SyntaxKind.ClassKeyword, SyntaxKind.StructKeyword);
            if (classOrStruct.Kind != SyntaxKind.None) {
                var kind = classOrStruct.Kind == SyntaxKind.ClassKeyword ?
                    SyntaxKind.ClassConstraint : SyntaxKind.StructConstraint;
                return Syntax.ClassOrStructConstraint(kind, classOrStruct);
            }

            // type constraint
            var type = TryGetType();
            if (type != null)
                return Syntax.TypeConstraint(type);

            // constructor constraint
            var newKeyword = TryGetToken(SyntaxKind.NewKeyword);
            if (newKeyword.Kind != SyntaxKind.None) {
                var openParen = GetToken(SyntaxKind.OpenParenToken);
                var closeParen = GetToken(SyntaxKind.CloseParenToken);
                return Syntax.ConstructorConstraint(
                    newKeyword, openParen, closeParen);
            }

            return default(TypeParameterConstraintSyntax);
        }
        private TypeParameterConstraintClauseSyntax TryGetConstraint() {
            var where = TryGetToken(SyntaxKind.WhereKeyword);
            if (where.Kind == SyntaxKind.None)
                return null;

            var identifier = GetIdentifierName();
            var colon = GetToken(SyntaxKind.ColonToken);
            var constraints = Constaints();

            return Syntax.TypeParameterConstraintClause(where, identifier, colon, constraints);
        }

        // separated lists
        private SeparatedSyntaxList<T> GetSeparatedList<T>(
            Func<T> tryGetNode, params SyntaxKind[] separatorKinds)
            where T : SyntaxNode {

            var nodesAndTokens = new List<SyntaxNodeOrToken>();
            while (true) {
                var node = tryGetNode();
                if (node == null)
                    break;
                nodesAndTokens.Add(node);

                var separator = TryGetToken(separatorKinds);
                if (separator.Kind == SyntaxKind.None)
                    break;
                nodesAndTokens.Add(separator);
            }

            return Syntax.SeparatedList<T>(nodesAndTokens);
        }
        private TypeParameterListSyntax TypeParameters() {

            var lessThan = TryGetToken(SyntaxKind.LessThanToken);
            if (lessThan.Kind == SyntaxKind.None)
                return null;

            var typeParameters = GetSeparatedList<TypeParameterSyntax>(
                GetNode<TypeParameterSyntax>, SyntaxKind.CommaToken);

            var greaterThan = GetToken(SyntaxKind.GreaterThanToken);

            return Syntax.TypeParameterList(lessThan, typeParameters, greaterThan);
        }
        private ParameterListSyntax Parameters() {
            var openParen = GetToken(SyntaxKind.OpenParenToken);
            var parameters = GetSeparatedList<ParameterSyntax>(
                TryGetNode<ParameterSyntax>, SyntaxKind.CommaToken);
            var closeParen = GetToken(SyntaxKind.CloseParenToken);

            return Syntax.ParameterList(openParen, parameters, closeParen);
        }
        private AttributeArgumentListSyntax AttributeArguments() {
            var openParen = TryGetToken(SyntaxKind.OpenParenToken);
            if (openParen.Kind == SyntaxKind.None)
                return null;
            var arguments = GetSeparatedList<AttributeArgumentSyntax>(
                TryGetNode<AttributeArgumentSyntax>, SyntaxKind.CommaToken);
            var closeParen = TryGetToken(SyntaxKind.CloseParenToken);

            return Syntax.AttributeArgumentList(openParen, arguments, closeParen);
        }
        private SeparatedSyntaxList<TypeSyntax> Types() {
            return GetSeparatedList<TypeSyntax>(GetType, SyntaxKind.CommaToken);
        }
        private SeparatedSyntaxList<TypeParameterConstraintSyntax> Constaints() {
            return GetSeparatedList<TypeParameterConstraintSyntax>(
                TryGetTypeParameterConstraint, SyntaxKind.CommaToken);
        }
        private SeparatedSyntaxList<AttributeSyntax> Attributes() {
            return GetSeparatedList<AttributeSyntax>(
                GetNode<AttributeSyntax>, SyntaxKind.CommaToken);
        }

        // lists
        private SyntaxList<T> GetList<T>(Func<T> tryGetNode) where T : SyntaxNode {
            var nodesAndTokens = new List<T>();

            while (true) {
                var node = tryGetNode();
                if (node == null)
                    break;
                nodesAndTokens.Add(node);
            }

            return Syntax.List<T>(nodesAndTokens);
        }
        private SyntaxList<TypeParameterConstraintClauseSyntax> Constraints() {
            return GetList<TypeParameterConstraintClauseSyntax>(TryGetConstraint);
        }
        private SyntaxList<AttributeListSyntax> AttributeGroups() {
            return GetList(TryGetNode<AttributeListSyntax>);
        }
        private SyntaxList<MemberDeclarationSyntax> Members() {
            return GetList(TryGetNode<MemberDeclarationSyntax>);
        }
        private SyntaxList<ExternAliasDirectiveSyntax> Externs() {
            return GetList(TryGetNode<ExternAliasDirectiveSyntax>);
        }
        private SyntaxList<UsingDirectiveSyntax> Usings() {
            return GetList(TryGetNode<UsingDirectiveSyntax>);
        }

        // larger nodes
        private BaseListSyntax BaseTypeAndInterfaces() {
            var colon = TryGetToken(SyntaxKind.ColonToken);
            if (colon.Kind == SyntaxKind.None)
                return default(BaseListSyntax);

            var types = Types();

            return Syntax.BaseList(colon, types);
        }
        private BlockSyntax TryGetBlock() {
            var openBrace = TryGetToken(SyntaxKind.OpenBraceToken);
            if (openBrace.Kind == SyntaxKind.None)
                return default(BlockSyntax);

            var statements = default(StatementSyntax);
            var closeBrace = GetToken(SyntaxKind.CloseBraceToken);
            return Syntax.Block(openBrace, statements, closeBrace);
        }
        private ExplicitInterfaceSpecifierSyntax TryGetExplicitInterfaceSpecifier() {
            var name = TryGetName();
            if (name == null)
                return default(ExplicitInterfaceSpecifierSyntax);

            var dot = GetToken(SyntaxKind.DotToken);

            return Syntax.ExplicitInterfaceSpecifier(name, dot);
        }
        #endregion

        // leaves
        internal TypeParameterSyntax GetTypeParameter() {
            var attributeDeclarations = AttributeGroups();
            var variance = TryGetToken(SyntaxKind.InKeyword, SyntaxKind.OutKeyword);
            var identifier = GetIdentifier();
            
            return Syntax.TypeParameter(attributeDeclarations, variance, identifier);
        }
        internal BaseTypeDeclarationSyntax GetTypeDeclaration() {

            var attributes = AttributeGroups();
            var modifiers = Modifiers();
            var keyword = GetKeyword();
            var identifier = GetIdentifier();
            var typeParameters = TypeParameters();
            var baseTypeAndInterfaces = BaseTypeAndInterfaces();
            var constraints = Constraints();
            var token = GetToken();

            #region Members
            var openBrace = default(SyntaxToken);
            var members = default(object);
            var closeBrace = default(SyntaxToken);
            var semicolon = default(SyntaxToken);

            if (token.Kind == SyntaxKind.OpenBraceToken) {
                openBrace = token;
                members = Members();
                closeBrace = GetToken(SyntaxKind.CloseBraceToken);
            } else {
                semicolon = token;
            }
            #endregion

            var result = default(BaseTypeDeclarationSyntax);

            switch (keyword.Kind) {
                #region Switch
                case SyntaxKind.ClassKeyword:
                    result = Syntax.ClassDeclaration(
                        attributes, modifiers, keyword, identifier, typeParameters,
                        baseTypeAndInterfaces, constraints, openBrace,
                        members != null ? (SyntaxList<MemberDeclarationSyntax>)members :
                            default(SyntaxList<MemberDeclarationSyntax>),
                        closeBrace, semicolon);
                    break;

                case SyntaxKind.InterfaceKeyword:
                    result = Syntax.InterfaceDeclaration(
                        attributes, modifiers, keyword, identifier, typeParameters,
                        baseTypeAndInterfaces, constraints, openBrace,
                        members != null ? (SyntaxList<MemberDeclarationSyntax>)members :
                            default(SyntaxList<MemberDeclarationSyntax>),
                        closeBrace, semicolon);
                    break;

                case SyntaxKind.StructKeyword:
                    result = Syntax.StructDeclaration(
                        attributes, modifiers, keyword, identifier, typeParameters,
                        baseTypeAndInterfaces, constraints, openBrace,
                        members != null ? (SyntaxList<MemberDeclarationSyntax>)members :
                            default(SyntaxList<MemberDeclarationSyntax>),
                        closeBrace, semicolon);
                    break;

                case SyntaxKind.EnumKeyword:
                    result = Syntax.EnumDeclaration(
                        attributes, modifiers, keyword, identifier,
                        baseTypeAndInterfaces, openBrace,
                        members != null ? (SeparatedSyntaxList<EnumMemberDeclarationSyntax>)members :
                            default(SeparatedSyntaxList<EnumMemberDeclarationSyntax>),
                        closeBrace, semicolon);
                    break;

                default:
                    throw new NotSupportedException();
                #endregion
            }

            return result;
        }
        internal MethodDeclarationSyntax GetMethodDeclaration() {
            var attributeGroups = AttributeGroups();
            var modifiers = Modifiers();
            var returnType = TryGetType();
            var explicitInterfaceSpecifier = TryGetExplicitInterfaceSpecifier();
            var identifier = GetIdentifier();
            var typeParameters = TypeParameters();
            var parameters = Parameters();
            var constraints = Constraints();
            var body = TryGetBlock();
            var semicolon = TryGetToken(SyntaxKind.SemicolonToken);
            
            return Syntax.MethodDeclaration(
                attributeGroups, modifiers, returnType,
                explicitInterfaceSpecifier, identifier,
                typeParameters, parameters, constraints,
                body, semicolon);
        }
        internal AttributeSyntax GetAttribute() {
            var name = GetName();
            var arguments = AttributeArguments();

            return Syntax.Attribute(name, arguments);
        }
        internal AttributeListSyntax TryGetAttributeGroup() {
            var openBracket = TryGetToken(SyntaxKind.OpenBracketToken);
            if (openBracket.Kind == SyntaxKind.None)
                return null;

            var target = default(AttributeTargetSpecifierSyntax);
            var keyword = TryGetKeyword();
            if (keyword.Kind != SyntaxKind.None) {
                var colon = GetToken(SyntaxKind.ColonToken);
                target = Syntax.AttributeTargetSpecifier(keyword, colon);
            }

            var attributes = Attributes();
            var closeBracket = GetToken(SyntaxKind.CloseBracketToken);

            return Syntax.AttributeList(openBracket, target, attributes, closeBracket);
        }
        internal AttributeArgumentSyntax TryGetAttributeArgument() {

            var name = TryGetIdentifierName();

            var nameEquals = default(NameEqualsSyntax);
            var nameColon = default(NameColonSyntax);
            var token = TryGetToken(SyntaxKind.ColonToken, SyntaxKind.EqualsToken);
            if (token.Kind == SyntaxKind.ColonToken)
                nameColon = Syntax.NameColon(name, token);
            else if (token.Kind == SyntaxKind.EqualsToken)
                nameEquals = Syntax.NameEquals(name, token);

            var expression = TryGetNode<ExpressionSyntax>();
            if (expression == null)
                return null;

            return Syntax.AttributeArgument(nameEquals, nameColon, expression);
        }
        internal ExpressionSyntax GetExpression() {
            return GetNode<ExpressionSyntax>();
        }
        internal UsingDirectiveSyntax GetUsingDeclaration() {
            var usng = GetKeyword();
            var identifier = TryGetIdentifierName();
            var alias = default(NameEqualsSyntax);
            if (identifier.Kind != SyntaxKind.None) {
                var equals = GetToken(SyntaxKind.EqualsToken);
                alias = Syntax.NameEquals(identifier, equals);
            }
            var name = GetName();
            var semicolon = GetToken(SyntaxKind.SemicolonToken);

            return Syntax.UsingDirective(usng, alias, name, semicolon);
        }
        internal NamespaceDeclarationSyntax GetNamespaceDeclaration() {
            var keyword = GetKeyword();
            var name = GetName();
            var openBrace = GetToken(SyntaxKind.OpenBraceToken);
            var externs = Externs();
            var usings = Usings();
            var members = Members();
            var closeBrace = GetToken(SyntaxKind.CloseBraceToken);
            var semiColon = TryGetToken(SyntaxKind.SemicolonToken);

            return Syntax.NamespaceDeclaration(
                keyword, name, openBrace, 
                    externs, usings, members, 
                closeBrace, semiColon);
        }
        internal ExternAliasDirectiveSyntax GetExternAliasDeclaration() {
            var externKeyword = GetKeyword();
            var aliasKeyword = GetKeyword();
            var identifier = GetIdentifier();
            var semiColon = GetToken(SyntaxKind.SemicolonToken);

            return Syntax.ExternAliasDirective(
                externKeyword, aliasKeyword, identifier, semiColon);
        }
        internal CompilationUnitSyntax GetCompilationUnit() {
            var externs = Externs();
            var usings = Usings();
            var attributes = AttributeGroups();
            var members = Members();
            var eof = GetEndOfFile();

            return Syntax.CompilationUnit(externs, usings, attributes, members, eof);
        }
    }
    internal sealed class CSharpSemanticModel {

        private CSharpCompilation m_compilation;
        private SemanticModel m_semanticModel;

        internal CSharpSemanticModel(SemanticModel semanticModel, CSharpCompilation compilationInfo) {
            m_semanticModel = semanticModel;
            m_compilation = compilationInfo;
        }

        internal CSharpTypeSyntax GetDeclarationType(SyntaxNode node) {
            // A syntax node that is a declaration. This can be any type derived from 
            // MemberDeclarationSyntax, TypeDeclarationSyntax, EnumDeclarationSyntax, NamespaceDeclarationSyntax,
            // ParameterSyntax, TypeParameterSyntax, or the alias part of a UsingDirectiveSyntax.
            //var symbol = m_semanticModel.GetDeclaredSymbol(node);

            //// dig out alias target
            //var alias = symbol as AliasSymbol;
            //if (alias != null)
            //    symbol = alias.Target;

            //return m_compilation.Get<CSharpTypeSymbol>(symbol);
            throw new NotImplementedException();
        }
    }

    [DebuggerDisplay(@"{GetType().Name,nq} = {DebugToString()}")]
    public abstract class CSharpObject : GenericDeclaration, IEnumerable<CSharpObject> {

        #region Definitions
        [Declaration(SubstituteTypes = new Type[] { 
            typeof(Type),
            typeof(Enum),
        })]
        private class CSharpSubstitute : TextDeclaration {

            private static CSharpCompilation s_mscorlib;

            static CSharpSubstitute() {
                s_mscorlib = new CSharpCompilation(
                    //libraryReferences: new[] {
                    //    typeof(object).Assembly.Location
                    //}
                );
            }

            private string GetTypeName(Type type) {

                // try return a keyword for the type
                //var info = s_mscorlib.TryGetType(type);
                //if (info != null && info.KeywordName != null) 
                //    return info.KeywordName;
                throw new NotImplementedException();
                //return type.Name;
            }

            protected override IEnumerable Substitute(DeclarationContext frame, object target) {
                var activator = frame.Ancestors(typeof(CSharpShiftReduce)).First();
                var local = (CSharpShiftReduce.Local)activator.Local;
                var inExpression = local.ExpressionDepth > 0;

                string result = null;

                if (target is Type) {
                    result = GetTypeName((Type)target);
                    if (inExpression)
                        result = "typeof(" + result + ")";
                } 
                
                else if (target is Enum) {
                    result = target.ToString();
                    if (inExpression)
                        result = target.GetType().Name + "." + result;
                }

                return result;
            }
        }

        [Declaration(SubstituteTypes = typeof(CSharpObject))]
        private class CSharpChildren : Declaration {

            private bool m_includeNodes;
            private bool m_includeTokens;
            private bool m_includeTrivia;

            internal CSharpChildren(
                bool includeNodes = false,
                bool includeTokens = false,
                bool includeTriva = false) {

                m_includeNodes = includeNodes;
                m_includeTokens = includeTokens;
                m_includeTrivia = includeTriva;
            }

            protected override IEnumerable Substitute(DeclarationContext frame, object target) {
                var parent = (CSharpObject)target;

                // return leading triva
                if (m_includeTrivia && parent is CSharpToken)
                    yield return parent.LeadingTrivia();

                // return token, node, or trivia
                if ((m_includeNodes && parent is CSharpNodeSyntax) ||
                    (m_includeTokens && parent is CSharpToken) ||
                    (m_includeTrivia && parent is CSharpTrivia))
                    yield return new Leaf(parent);

                // return trailing triva
                if (m_includeTrivia && parent is CSharpToken)
                    yield return parent.TrailingTrivia();

                // recurse through children
                var node = parent as CSharpNodeSyntax;
                if (node != null)
                    yield return node.Children();
            }
        }
        #endregion

        internal static Func<object, T> Transform<T>(Func<object, T> transform) {
            Func<object, T> result =
                delegate(object o) {
                    if (o is T)
                        return (T)o;
                    return transform(o);
                };

            return result;
        }

        #region Activation
        internal static CSharpObject Activate(object syntax, CSharpObject parent = null, CSharpSemanticModel semanticModel = null) {
            SyntaxKind kind = SyntaxKind.None;

            if (syntax is SyntaxNode) kind = ((SyntaxNode)syntax).Kind;
            else if (syntax is SyntaxToken) kind = ((SyntaxToken)syntax).Kind;
            else if (syntax is SyntaxTrivia) kind = ((SyntaxTrivia)syntax).Kind;
            else if (syntax is SyntaxNodeOrToken) kind = ((SyntaxNodeOrToken)syntax).Kind;
            else throw new NotImplementedException();

            var info = CSharpLoader.TryGetNodeInfo(kind);
            if (info == null)
                throw new NotImplementedException();

            return (CSharpObject)info.Type.Activate(syntax, parent, semanticModel);
        }
        #endregion

        #region Private Data Members
        private CSharpObject m_parent;
        private object m_children;
        private CSharpSemanticModel m_semanticModel;
        #endregion

        #region Constructors
        internal CSharpObject() { }
        internal CSharpObject(object children) {
            m_children = children;
        }
        internal CSharpObject(CSharpObject parent, CSharpSemanticModel semanticModel) {
            m_parent = parent;
            m_semanticModel = semanticModel;
        }
        #endregion

        #region Internal Members
        internal object Builder {
            get { return m_children; }
        }

        internal virtual SyntaxTrivia SyntaxTrivia {
            get { throw new InvalidOperationException(); }
        }
        internal virtual SyntaxNode SyntaxNode {
            get { throw new InvalidOperationException(); }
        }
        internal virtual SyntaxToken SyntaxToken {
            get { throw new InvalidOperationException(); }
        }
        internal abstract bool IsInitialized { get; }

        internal virtual SyntaxNodeOrToken Reduce(SyntaxBinder binder) {
            Contract.Assert(m_children == null);
            Contract.Assert(base.Children() == null);
            return SyntaxToken;
        }
        internal virtual SyntaxNodeOrToken Parse(string text) {
            throw new NotSupportedException();
        }
        internal virtual SyntaxTriviaList ParseTrivia(string text) {
            throw new NotSupportedException();
        }
        #endregion

        #region Declaration Members
        protected sealed override void DeinitializeFrame(DeclarationContext frame) {
            var activatorFrame = frame.Ancestors(typeof(CSharpShiftReduce)).First();
            var activator = (CSharpShiftReduce)activatorFrame.Object;
            activator.Reduce(activatorFrame, this);
        }
        protected sealed override IEnumerable Substance() {
            return Children(default(DeclarationContext));
        }
        protected sealed override IEnumerable Children(DeclarationContext frame) {
            var children = m_children;
            if (children == null)
                children = base.Children();

            if (children == null && IsInitialized)
                children = CSharpLeaf.Singleton;

            if (children == null)
                return null;

            var enumerable = children as IEnumerable;
            if (enumerable != null)
                return enumerable;

            return new[] { children };
        }
        #endregion

        #region Protected Members
        protected object Initialize() {

            // the stack of tokens that is reduced to a node or token
            return new CSharpShiftReduce { 

                // track start lines
                new TextStartLineDetector {

                    // substitute unknown types by calling .ToString
                    new TextUnknownObjectToString {

                        // substitute some types (e.g. Type) instead of just calling .ToString
                        new CSharpSubstitute { this }
                    }
                }
            }.SingleOrDefault();
        }
        protected virtual IEnumerable NodesAndTokens(DeclarationContext frame) {
            throw new NotImplementedException();
        }
        protected IEnumerable<T> Get<T>(ref IEnumerable<T> location, IEnumerable syntax) where T : CSharpObject {
            if (location == null)
                location = syntax.Cast<object>().Select(o => (T)Activate(o, this, m_semanticModel)).ToArray();
            return location;
        }
        protected T Get<T>(ref T location, SyntaxToken syntaxToken) where T : CSharpToken {
            if (location == null)
                location = (T)Activate(syntaxToken, this, m_semanticModel);
            return location;
        }
        protected T Get<T>(ref T location, SyntaxNode syntaxNode) where T : CSharpNodeSyntax {
            if (location == null)
                location = (T)Activate(syntaxNode, this, m_semanticModel);
            return location;
        }
        #endregion

        internal CSharpNodeInfo GetInfo() {
            return CSharpLoader.GetNodeInfo(GetType());
        }
        internal CSharpSemanticModel SemanticModel {
            get {
                if (m_semanticModel == null)
                    throw new InvalidOperationException("Semantic information unavailable.");
                return m_semanticModel; 
            }
        }

        #region Public Members
        public CSharpObject Parent {
            get { return m_parent; }
        }
        public IEnumerable<CSharpObject> Children(
            bool includeNodes = false,
            bool includeTokens = false,
            bool includeTriva = false) {
            throw new NotImplementedException();
        }
        public IEnumerable<CSharpObject> Descendents(
            bool includeSelf = false, 
            bool includeNodes = false, 
            bool includeTokens = false, 
            bool includeTriva = false) {

            var result = new CSharpChildren(
                includeNodes: includeNodes,
                includeTokens: includeTokens, 
                includeTriva: includeTriva) 
                { this }.Cast<CSharpObject>();

            if (!includeSelf) {
                if ((this is CSharpNodeSyntax && includeNodes) ||
                    (this is CSharpToken && includeTokens) ||
                    (this is CSharpTrivia && includeTriva))
                    result = result.Skip(1);
            }

            return result;
        }
        public abstract string ToString(bool withTrivia = true);
        public abstract object Value { get; }
        public abstract IEnumerable<CSharpTrivia> LeadingTrivia();
        public abstract IEnumerable<CSharpTrivia> TrailingTrivia();
        #endregion

        #region IEnumerable
        public new virtual IEnumerator<CSharpObject> GetEnumerator() {
            return Descendents(includeTokens: true).GetEnumerator();
        }
        IEnumerator IEnumerable.GetEnumerator() {
            return GetEnumerator();
        }
        public sealed override void Add(object o) {
            if (m_children == null) {
                base.Add(o);
                return;
            }

            var declaration = m_children as GenericDeclaration;
            if (declaration == null)
                throw new NotImplementedException();

            declaration.Add(o);
        }
        #endregion

        public override string ToString() {
            return ToString(withTrivia: true);
        }
        private string DebugToString() {
            return IsInitialized ? ToString() : "(uninitialized)";
        }
    }
    [Declaration(IsLeaf = true)]
    internal sealed class CSharpLeaf : Declaration {
        internal static readonly CSharpLeaf Singleton = new CSharpLeaf();
        protected override object GetLeaf(DeclarationContext frame) {
            return Vanish;
        }
    }

    // trivia
    public abstract class CSharpTrivia : CSharpObject {
        private bool m_initialized;
        private SyntaxTrivia m_trivia;

        internal CSharpTrivia() { }
        internal CSharpTrivia(SyntaxTrivia trivia, CSharpObject parent, CSharpSemanticModel semanticModel)
            : base(parent, semanticModel) {

            Initialize(trivia);
        }

        private void Initialize(SyntaxTrivia trivia) {
            m_trivia = trivia;
            m_initialized = true;
        }
        private new void Initialize() {
            if (m_initialized)
                return;

            Initialize((SyntaxTrivia)base.Initialize());
        }

        internal override bool IsInitialized {
            get { return m_initialized; }
        }
        internal override SyntaxTrivia SyntaxTrivia {
            get { return m_trivia; }
        }

        public override IEnumerable<CSharpTrivia> LeadingTrivia() {
            yield break;
        }
        public override IEnumerable<CSharpTrivia> TrailingTrivia() {
            yield break;
        }
        public override string ToString(bool withTrivia = true) {
            return withTrivia ? SyntaxTrivia.ToFullString() : SyntaxTrivia.ToString();
        }

        public override object Value {
            get { return ToString(withTrivia: false); }
        }
    }
    [CSharpSymbol(SyntaxKind.WhitespaceTrivia)]
    public sealed class CSharpWhitespaceTrivia : CSharpTrivia {
        public CSharpWhitespaceTrivia() { }
        internal CSharpWhitespaceTrivia(SyntaxTrivia trivia, CSharpObject parent, CSharpSemanticModel semanticModel)
            : base(trivia, parent, semanticModel) {
        }

        internal override SyntaxTriviaList ParseTrivia(string text) {
            return Syntax.ParseLeadingTrivia(text);
        }
    }
    [CSharpSymbol(SyntaxKind.EndOfLineTrivia)]
    public sealed class CSharpEndOfLineTrivia : CSharpTrivia {
        public CSharpEndOfLineTrivia() { }
        internal CSharpEndOfLineTrivia(SyntaxTrivia trivia, CSharpObject parent, CSharpSemanticModel semanticModel)
            : base(trivia, parent, semanticModel) {
        }

        internal override SyntaxTriviaList ParseTrivia(string text) {
            return Syntax.ParseLeadingTrivia(text);
        }
    }
    [CSharpSymbol(SyntaxKind.SingleLineCommentTrivia)]
    public sealed class SingleLineCommentLineTrivia : CSharpTrivia {
        public SingleLineCommentLineTrivia() { }
        internal SingleLineCommentLineTrivia(SyntaxTrivia trivia, CSharpObject parent, CSharpSemanticModel semanticModel)
            : base(trivia, parent, semanticModel) {
        }

        internal override SyntaxTriviaList ParseTrivia(string text) {
            return Syntax.ParseLeadingTrivia(text);
        }
    }

    // tokens
    public abstract class CSharpToken : CSharpObject {

        internal static void LoadTokens(Type type, string suffix) {
            var fieldsAndKeywords =
                from field in type.Get<FieldInfo>()
                join keyword in typeof(SyntaxKind).GetFields()
                    on field.Name + suffix equals keyword.Name
                select new {
                    Field = field,
                    Keyword = keyword
                };

            foreach (var o in fieldsAndKeywords) {
                var value =  o.Field.FieldType.Activate(Syntax.Token((SyntaxKind)o.Keyword.GetValue()));
                o.Field.SetStaticValue(value);
            }
        }

        private bool m_initialized;
        private SyntaxToken m_token;
        private IEnumerable<CSharpTrivia> m_leadingTrivia;
        private IEnumerable<CSharpTrivia> m_trailingTrivia;

        internal CSharpToken() { 
        }
        internal CSharpToken(SyntaxToken token) {
            Initialize(token);
        }
        internal CSharpToken(SyntaxToken token, CSharpObject parent, CSharpSemanticModel semanticModel)
            : base(parent, semanticModel) {

            Initialize(token);
        }

        private void Initialize(SyntaxToken token) {
            m_token = token;
            m_initialized = true;
        }
        private new void Initialize() {
            if (m_initialized)
                return;
            Initialize((SyntaxToken)base.Initialize());
        }

        internal override SyntaxToken SyntaxToken {
            get {
                Initialize();
                return m_token; 
            }
        }
        internal override bool IsInitialized {
            get { return m_initialized; }
        }

        internal override SyntaxNodeOrToken Parse(string text) {
            var syntaxToken = Syntax.ParseToken(text);

            // context sensitive keywords
            if (this is CSharpKeywordToken && syntaxToken.Kind == SyntaxKind.IdentifierToken)
                syntaxToken = Syntax.Token(
                    syntaxToken.LeadingTrivia,
                    CSharpKeywordToken.GetKeyword(syntaxToken.ValueText),
                    syntaxToken.TrailingTrivia);

            if (!GetInfo().Kinds().Contains(syntaxToken.Kind))
                throw new ArgumentException("Expected token of type " + GetInfo().Kinds().StringJoin(" or ") +
                    " but parsed token of is of type " + syntaxToken.Kind + ".");

            return syntaxToken;
        }

        public override string ToString(bool withTrivia = true) {
            return withTrivia ? SyntaxToken.ToFullString() : SyntaxToken.ToString();
        }
        public override object Value {
            get { return SyntaxToken.Value; }
        }
        public override IEnumerable<CSharpTrivia> LeadingTrivia() {
            return Get<CSharpTrivia>(ref m_leadingTrivia, SyntaxToken.LeadingTrivia.Where(o => o.FullSpan.Length > 0));
        }
        public override IEnumerable<CSharpTrivia> TrailingTrivia() {
            return Get<CSharpTrivia>(ref m_trailingTrivia, SyntaxToken.TrailingTrivia.Where(o => o.FullSpan.Length > 0));
        }
    }
    [Declaration]
    public abstract class CSharpKeywordToken : CSharpToken {

        static CSharpKeywordToken() {
            CSharpToken.LoadTokens(typeof(CSharpKeywordToken), "Keyword");

            var keywords =
                from field in typeof(SyntaxKind).GetFields()
                where field.Name.EndsWith("Keyword")
                select new {
                    Keyword = field.Name.Remove("Keyword").ToLower(),
                    SyntaxKind = (SyntaxKind)field.GetValue()
                };

            s_keywords = keywords.ToDictionary(o => o.Keyword, o => o.SyntaxKind);
        }

        internal static SyntaxKind GetKeyword(string keyword) {
            return s_keywords[keyword];
        }
        private static Dictionary<string, SyntaxKind> s_keywords;

        #region Singletons
        #pragma warning disable 0649
        // types
        public static CSharpBoolKeyword Bool;
        public static CSharpByteKeyword Byte;
        public static CSharpSByteKeyword SByte;
        public static CSharpShortKeyword Short;
        public static CSharpUShortKeyword UShort;
        public static CSharpIntKeyword Int;
        public static CSharpUIntKeyword UInt;
        public static CSharpLongKeyword Long;
        public static CSharpULongKeyword ULong;
        public static CSharpDoubleKeyword Double;
        public static CSharpFloatKeyword Float;
        public static CSharpDecimalKeyword Decimal;
        public static CSharpStringKeyword String;
        public static CSharpCharKeyword Char;
        public static CSharpVoidKeyword Void;
        public static CSharpObjectKeyword Object;
        public static CSharpNullKeyword Null;

        // literals
        public static CSharpTrueKeyword True;
        public static CSharpFalseKeyword False;

        // control flow
        public static CSharpIfKeyword If;
        public static CSharpElseKeyword Else;
        public static CSharpWhileKeyword While;
        public static CSharpForKeyword For;
        public static CSharpForEachKeyword ForEach;
        public static CSharpDoKeyword Do;
        public static CSharpBreakKeyword Break;
        public static CSharpContinueKeyword Continue;

        // switch
        public static CSharpSwitchKeyword Switch;
        public static CSharpCaseKeyword Case;
        public static CSharpDefaultKeyword Default;

        // jumps
        public static CSharpGotoKeyword Goto;
        public static CSharpReturnKeyword Return;
        public static CSharpYieldKeyword Yield;

        // exceptions
        public static CSharpThrowKeyword Throw;
        public static CSharpTryKeyword Try;
        public static CSharpCatchKeyword Catch;
        public static CSharpFinallyKeyword Finally;

        // visibility
        public static CSharpPublicKeyword Public;
        public static CSharpPrivateKeyword Private;
        public static CSharpInternalKeyword Internal;
        public static CSharpProtectedKeyword Protected;

        // modifiers
        public static CSharpStaticKeyword Static;
        public static CSharpReadOnlyKeyword ReadOnly;
        public static CSharpSealedKeyword Sealed;
        public static CSharpConstKeyword Const;
        public static CSharpFixedKeyword Fixed;
        public static CSharpStackAllocKeyword StackAlloc;
        public static CSharpUnsafeKeyword Unsafe;
        public static CSharpPartialKeyword Partial;
        public static CSharpExternKeyword Extern;
        public static CSharpNewKeyword New;
        public static CSharpOverrideKeyword Override;
        public static CSharpAbstractKeyword Abstract;
        public static CSharpVirtualKeyword Virtual;

        // type checking
        public static CSharpIsKeyword Is;
        public static CSharpAsKeyword As;
        public static CSharpTypeOfKeyword TypeOf;
        public static CSharpSizeOfKeyword SizeOf;

        // parameter modifiers
        public static CSharpRefKeyword Ref;
        public static CSharpOutKeyword Out;
        public static CSharpInKeyword In;
        public static CSharpParamsKeyword Params;

        // variables
        public static CSharpArgListKeyword ArgList;
        public static CSharpLockKeyword Lock;
        public static CSharpVarKeyword Var;
        //public static CSharpDynamicKeyword Dynamic;
        public static CSharpCheckedKeyword Checked;
        public static CSharpUncheckedKeyword Unchecked;

        // esoteric
        public static CSharpMakeRefKeyword MakeRef;
        public static CSharpRefTypeKeyword RefType;
        public static CSharpRefValueKeyword RefValue;
        public static CSharpVolatileKeyword Volatile;
        public static CSharpAliasKeyword Alias;
        public static CSharpGlobalKeyword Global;
        public static CSharpTypeVarKeyword TypeVar;

        // activation
        public static CSharpThisKeyword This;
        public static CSharpBaseKeyword Base;

        // scope
        public static CSharpNamespaceKeyword Namespace;
        public static CSharpUsingKeyword Using;

        // type of types
        public static CSharpClassKeyword Class;
        public static CSharpStructKeyword Struct;
        public static CSharpInterfaceKeyword Interface;
        public static CSharpEnumKeyword Enum;
        public static CSharpDelegateKeyword Delegate;

        // custom operators
        public static CSharpOperatorKeyword Operator;
        public static CSharpExplicitKeyword Explicit;
        public static CSharpImplicitKeyword Implicit;

        // attribute targets
        public static CSharpAssemblyKeyword Assembly;
        public static CSharpModuleKeyword Module;
        public static CSharpTypeKeyword Type;
        public static CSharpFieldKeyword Field;
        public static CSharpMethodKeyword Method;
        public static CSharpParamKeyword Param;
        public static CSharpPropertyKeyword Property;
        public static CSharpEventKeyword Event;

        // accessors
        public static CSharpGetKeyword Get;
        public static CSharpSetKeyword Set;
        public static new CSharpAddKeyword Add;
        public static CSharpRemoveKeyword Remove;
        public static CSharpValueKeyword Value;

        // linq
        public static CSharpFromKeyword From;
        public static CSharpWhereKeyword Where;
        public static CSharpGroupKeyword Group;
        public static CSharpJoinKeyword Join;
        public static CSharpIntoKeyword Into;
        public static CSharpLetKeyword Let;
        public static CSharpByKeyword By;
        public static CSharpSelectKeyword Select;
        public static CSharpOrderByKeyword OrderBy;
        public static CSharpOnKeyword On;
        public static new CSharpEqualsKeyword Equals;
        public static CSharpAscendingKeyword Ascending;
        public static CSharpDescendingKeyword Descending;

        // pre-processor
        public static CSharpElifKeyword Elif;
        public static CSharpEndIfKeyword EndIf;
        public static CSharpRegionKeyword Region;
        public static CSharpEndRegionKeyword EndRegion;
        public static CSharpDefineKeyword Define;
        public static CSharpUndefKeyword Undef;
        public static CSharpWarningKeyword Warning;
        public static CSharpErrorKeyword Error;
        public static CSharpLineKeyword Line;
        public static CSharpPragmaKeyword Pragma;
        public static CSharpHiddenKeyword Hidden;
        public static CSharpChecksumKeyword Checksum;
        public static CSharpDisableKeyword Disable;
        public static CSharpRestoreKeyword Restore;
        #pragma warning restore 0649
        #endregion

        internal CSharpKeywordToken() { }
        internal CSharpKeywordToken(SyntaxToken token)
            : base(token) {
        }
        internal CSharpKeywordToken(SyntaxToken token, CSharpObject parent, CSharpSemanticModel semanticModel)
            : base(token, parent, semanticModel) {
        }
    }
    [Declaration]
    public abstract class CSharpPunctuationToken : CSharpToken {

        static CSharpPunctuationToken() {
            CSharpToken.LoadTokens(typeof(CSharpPunctuationToken), "Token");
        }

        #region Singletons
        #pragma warning disable 0649
        // arithmetic
        public static readonly CSharpMinusToken Minus;
        public static readonly CSharpPlusToken Plus;
        public static readonly CSharpPercentToken Percent;
        public static readonly CSharpAsteriskToken Asterisk;
        public static readonly CSharpSlashToken Slash;

        // assignment
        public static readonly new CSharpEqualsToken Equals;
        public static readonly CSharpAmpersandEqualsToken AmpersandEquals;
        public static readonly CSharpPlusEqualsToken PlusEquals;
        public static readonly CSharpMinusEqualsToken MinusEquals;
        public static readonly CSharpCaretEqualsToken CaretEquals;
        public static readonly CSharpPercentEqualsToken PercentEquals;
        public static readonly CSharpSlashEqualsToken SlashEquals;
        public static readonly CSharpAsteriskEqualsToken AsteriskEquals;
        public static readonly CSharpBarEqualsToken BarEquals;
        public static readonly CSharpGreaterThanGreaterThanEqualsToken GreaterThanGreaterThanEquals;
        public static readonly CSharpLessThanLessThanEqualsToken LessThanLessThanEquals;
        public static readonly CSharpExclamationEqualsToken ExclamationEquals;

        // logical
        public static readonly CSharpBarBarToken BarBar;
        public static readonly CSharpAmpersandAmpersandToken AmpersandAmpersand;

        // testing
        public static readonly CSharpEqualsEqualsToken EqualsEquals;
        public static readonly CSharpLessThanToken LessThan;
        public static readonly CSharpGreaterThanToken GreaterThan;
        public static readonly CSharpLessThanEqualsToken LessThanEquals;
        public static readonly CSharpGreaterThanEqualsToken GreaterThanEquals;
        public static readonly CSharpQuestionQuestionToken QuestionQuestion;

        // bit manipulation
        public static readonly CSharpTildeToken Tilde;
        public static readonly CSharpExclamationToken Exclamation;
        public static readonly CSharpCaretToken Caret;
        public static readonly CSharpAmpersandToken Ampersand;
        public static readonly CSharpBarToken Bar;
        public static readonly CSharpGreaterThanGreaterThanToken GreaterThanGreaterThan;
        public static readonly CSharpLessThanLessThanToken LessThanLessThan;

        // single tokens
        public static readonly CSharpDollarToken Dollar;
        public static readonly CSharpBackslashToken Backslash;
        public static readonly CSharpColonToken Colon;
        public static readonly CSharpSemicolonToken Semicolon;
        public static readonly CSharpDoubleQuoteToken DoubleQuote;
        public static readonly CSharpSingleQuoteToken SingleQuote;
        public static readonly CSharpCommaToken Comma;
        public static readonly CSharpDotToken Dot;
        public static readonly CSharpQuestionToken Question;
        public static readonly CSharpHashToken Hash;

        // groupings
        public static readonly CSharpOpenParenToken OpenParen;
        public static readonly CSharpCloseParenToken CloseParen;
        public static readonly CSharpOpenBraceToken OpenBrace;
        public static readonly CSharpCloseBraceToken CloseBrace;
        public static readonly CSharpOpenBracketToken OpenBracket;
        public static readonly CSharpCloseBracketToken CloseBracket;

        // pointers
        public static readonly CSharpSlashGreaterThanToken SlashGreaterThan;
        public static readonly CSharpLessThanSlashToken LessThanSlash;

        // inc/dec
        public static readonly CSharpMinusMinusToken MinusMinus;
        public static readonly CSharpPlusPlusToken PlusPlus;

        // scope
        public static readonly CSharpColonColonToken ColonColon;

        // pointer
        public static readonly CSharpMinusGreaterThanToken MinusGreaterThan;

        // lambda
        public static readonly CSharpEqualsGreaterThanToken EqualsGreaterThan;
        #pragma warning restore 0649
        #endregion

        public CSharpPunctuationToken() { }
        internal CSharpPunctuationToken(SyntaxToken token)
            : base(token) {
        }
        internal CSharpPunctuationToken(SyntaxToken token, CSharpObject parent, CSharpSemanticModel semanticModel)
            : base(token, parent, semanticModel) {
        }
    }
    [CSharpSymbol(SyntaxKind.IdentifierToken)]
    public sealed class CSharpIdentifierToken : CSharpToken {

        public CSharpIdentifierToken() { }
        internal CSharpIdentifierToken(SyntaxToken token, CSharpObject parent, CSharpSemanticModel semanticModel)
            : base(token, parent, semanticModel) {
        }
    }
    [CSharpSymbol(SyntaxKind.EndOfFileToken), Declaration]
    public sealed class CSharpEndOfFlieToken : CSharpToken {

        public CSharpEndOfFlieToken() 
            : base(Syntax.Token(SyntaxKind.EndOfFileToken)) { }
        internal CSharpEndOfFlieToken(SyntaxToken token, CSharpObject parent, CSharpSemanticModel semanticModel)
            : base(token, parent, semanticModel) {
        }
    }

    #region Tokens
    #region Literals
    //NumericLiteralToken,
    //CharacterLiteralToken,
    //StringLiteralToken,
    #endregion

    #region Other
    //IdentifierToken,

    //EndOfDirectiveToken,
    //EndOfFileToken,
    //BadToken,
    #endregion

    #region Documentation Comment
    // tokens
    //XmlEntityLiteralToken,
    //XmlTextLiteralToken,
    //XmlTextLiteralNewLineToken,
    //XmlCommentStartToken,
    //XmlCommentEndToken,
    //XmlCDataStartToken,
    //XmlCDataEndToken,
    //XmlProcessingInstructionStartToken,
    //XmlProcessingInstructionEndToken,
    //EndOfDocumentationCommentToken,

    // trivia
    //DocumentationCommentExteriorTrivia,

    // productions
    //XmlProcessingInstruction,
    //DocumentationComment,
    //XmlElement,
    //XmlElementStartTag,
    //XmlElementEndTag,
    //XmlEmptyElement,
    //XmlAttribute,
    //XmlName,
    //XmlPrefix,
    //XmlText,
    //XmlCDataSection,
    //XmlComment,
    #endregion

    #region Trivia
    //EndOfLineTrivia,
    //WhitespaceTrivia,
    //SingleLineCommentTrivia,
    //MultiLineCommentTrivia,
    #endregion

    #region Directives
    //IfDirective,
    //ElifDirective,
    //ElseDirective,
    //EndIfDirective,
    //RegionDirective,
    //EndRegionDirective,
    //DefineDirective,
    //UndefDirective,
    //ErrorDirective,
    //WarningDirective,
    //LineDirective,
    //PragmaWarningDirective,
    //PragmaChecksumDirective,
    //ReferenceDirective,
    //BadDirective,

    //PreprocessingMessageTrivia,
    //DisabledTextTrivia,
    #endregion

    #region Expression
    //ParenthesizedExpression,
    //InvocationExpression,
    //ElementAccessExpression,
    //CastExpression,
    //AnonymousMethodExpression,
    //SimpleLambdaExpression,
    //ParenthesizedLambdaExpression,
    //InitializerExpression,
    //ObjectCreationExpression,
    //AnonymousObjectCreationExpression,
    //ArrayCreationExpression,
    //ImplicitArrayCreationExpression,
    //StackAllocArrayCreationExpression,
    //AddExpression,
    //SubtractExpression,
    //MultiplyExpression,
    //DivideExpression,
    //ModuloExpression,
    //LeftShiftExpression,
    //RightShiftExpression,
    //LogicalOrExpression,
    //LogicalAndExpression,
    //BitwiseOrExpression,
    //BitwiseAndExpression,
    //ExclusiveOrExpression,
    //EqualsExpression,
    //NotEqualsExpression,
    //LessThanExpression,
    //LessThanOrEqualExpression,
    //GreaterThanExpression,
    //GreaterThanOrEqualExpression,
    //IsExpression,
    //AsExpression,
    //CoalesceExpression,
    //MemberAccessExpression,
    //PointerMemberAccessExpression,
    //AssignExpression,
    //AddAssignExpression,
    //SubtractAssignExpression,
    //MultiplyAssignExpression,
    //DivideAssignExpression,
    //ModuloAssignExpression,
    //AndAssignExpression,
    //ExclusiveOrAssignExpression,
    //OrAssignExpression,
    //LeftShiftAssignExpression,
    //RightShiftAssignExpression,
    //PlusExpression,
    //NegateExpression,
    //BitwiseNotExpression,
    //LogicalNotExpression,
    //PreIncrementExpression,
    //PreDecrementExpression,
    //PointerIndirectionExpression,
    //AddressOfExpression,
    //PostIncrementExpression,
    //PostDecrementExpression,
    //ThisExpression,
    //BaseExpression,
    //ArgListExpression,
    //NumericLiteralExpression,
    //StringLiteralExpression,
    //CharacterLiteralExpression,
    //TrueLiteralExpression,
    //FalseLiteralExpression,
    //NullLiteralExpression,
    //TypeOfExpression,
    //SizeOfExpression,
    //CheckedExpression,
    //UncheckedExpression,
    //DefaultExpression,
    //MakeRefExpression,
    //RefValueExpression,
    //RefTypeExpression,
    //QueryExpression,
    #endregion

    #region Statements
    //LocalDeclarationStatement,
    //EmptyStatement,
    //LabeledStatement,
    //GotoStatement,
    //GotoCaseStatement,
    //GotoDefaultStatement,
    //BreakStatement,
    //ContinueStatement,
    //ReturnStatement,
    //YieldReturnStatement,
    //YieldBreakStatement,
    //ThrowStatement,
    //WhileStatement,
    //DoStatement,
    //ForStatement,
    //ForEachStatement,
    //UsingStatement,
    //FixedStatement,
    //CheckedStatement,
    //UncheckedStatement,
    //UnsafeStatement,
    //LockStatement,
    //IfStatement,
    //SwitchStatement,
    //TryStatement,
    //GlobalStatement,
    #endregion

    #region Clauses
    //FromClause,
    //LetClause,
    //JoinClause,
    //JoinIntoClause,
    //WhereClause,
    //OrderByClause,
    //SelectClause,
    //GroupClause,
    //EqualsValueClause,
    //ElseClause,
    //CatchClause,
    //FinallyClause,
    //TypeParameterConstraintClause,

    //AscendingOrdering,
    //DescendingOrdering,
    //QueryContinuation,
    #endregion

    #region Other
    //None,
    //List,
    //IncompleteMember,

    //SkippedTokens,

    //IdentifierName,
    //QualifiedName,
    //GenericName,
    //AliasQualifiedName,
    //PredefinedType,

    //ArrayType,
    //ArrayRankSpecifier,
    //PointerType,
    //NullableType,

    //Parameter,
    //ParameterList,
    //BracketedParameterList,
    //AccessorList,
    //NameColon,
    //NameEquals,
    //Argument,
    //ArgumentList,
    //BracketedArgumentList,

    //TypeParameter,
    //TypeParameterList,
    //TypeConstraint,
    //ClassConstraint,
    //StructConstraint,
    //TypeArgumentList,

    //Block,

    //VariableDeclarator,

    //SwitchSection,
    //CaseSwitchLabel,
    //DefaultSwitchLabel,

    //CompilationUnit,

    //AttributeTargetSpecifier,
    //Attribute,
    //AttributeArgumentList,
    //AttributeArgument,

    //BaseList,
    //ConstructorConstraint,
    //BaseConstructorInitializer,
    //ThisConstructorInitializer,

    //ExplicitInterfaceSpecifier,
    #endregion
    #endregion

    // nodes
    [Declaration(UseDedicatedStack = true)]
    public abstract class CSharpNodeSyntax : CSharpObject {
        private bool m_initialized;
        private SyntaxNode m_node;

        internal CSharpNodeSyntax() {
        }
        internal CSharpNodeSyntax(object value) 
            : base(value) {
        }
        internal CSharpNodeSyntax(SyntaxNode node, CSharpObject parent, CSharpSemanticModel semanticModel)
            : base(parent, semanticModel) {
            Initialize(node);
        }

        private void Initialize(SyntaxNode node) {
            m_node = node;
            m_initialized = true;
        }
        private new void Initialize() {
            if (m_initialized)
                return;
            Initialize((SyntaxNode)base.Initialize());
        }

        internal override bool IsInitialized {
            get { return m_initialized; }
        }
        internal override SyntaxNode SyntaxNode {
            get {
                Initialize();
                if (m_node == null)
                    throw new InvalidOperationException("Node is vacuous.");
                return m_node; 
            }
        }
        internal new virtual IEnumerable Children() {
            yield break;
        }

        public override IEnumerable<CSharpTrivia> LeadingTrivia() {
            yield break;
        }
        public override IEnumerable<CSharpTrivia> TrailingTrivia() {
            yield break;
        }
        public override string ToString(bool withTrivia = true) {
            return withTrivia ? SyntaxNode.ToFullString() : SyntaxNode.ToString();
        }
        public override object Value {
            get { return null; }
        }
    }

    // leaf nodes
    [CSharpSymbol(
        SyntaxKind.ArrayType,
        SyntaxKind.NullableType,
        SyntaxKind.PointerType,
        SyntaxKind.PredefinedType,
        SyntaxKind.AliasQualifiedName,
        SyntaxKind.QualifiedName,
        SyntaxKind.IdentifierName, 
        SyntaxKind.GenericName)]
    public class CSharpName : CSharpNodeSyntax {

        #region Definitions
        private abstract class RootData {
            internal static RootData Activate(CSharpName csharpName) {
                var syntax = csharpName.SyntaxNode;
                if (syntax is NullableTypeSyntax) return new NullableTypeData(csharpName);
                if (syntax is PointerTypeSyntax) return new PointerTypeData(csharpName);
                if (syntax is ArrayTypeSyntax) return new ArrayTypeData(csharpName);
                if (syntax is PredefinedTypeSyntax) return new PredefinedTypeData(csharpName);

                if (syntax is AliasQualifiedNameSyntax) return new AliasQualifiedNameData(csharpName);
                if (syntax is QualifiedNameSyntax) return new QualifiedNameData(csharpName);

                if (syntax is GenericNameSyntax) return new GenericNameData(csharpName);
                if (syntax is IdentifierNameSyntax) return new IdentifierNameData(csharpName);
                throw new ArgumentException();
            }

            private CSharpName m_csharpName;

            internal RootData(CSharpName csharpName) {
                m_csharpName = csharpName;
            }

            internal CSharpName CSharpName {
                get { return m_csharpName; }
            }
            internal SyntaxNode SyntaxNode {
                get { return m_csharpName.SyntaxNode; }
            }

            internal virtual CSharpName ElementTypeNode {
                get { return null; }
            }
            internal virtual CSharpName UndecoratedNode {
                get { return CSharpName; }
            }

            internal virtual CSharpIdentifierToken AliasIdentifierToken {
                get { return null; }
            }
            internal virtual CSharpColonColonToken ColonColonToken {
                get { return null; }
            }
            internal virtual CSharpQuestionToken QuestionToken {
                get { return null; }
            }
            internal virtual CSharpAsteriskToken AsteriskToken {
                get { return null; }
            }
            internal virtual IEnumerable<CSharpArrayRankSpecifierSyntax> RankSpecifierNodes() {
                yield break;
            }
            internal virtual CSharpKeywordToken KeywordToken {
                get { return null; }
            }
            internal virtual CSharpIdentifierToken IdentifierToken {
                get { return null; }
            }
            internal virtual CSharpDotToken DotToken {
                get { return null; }
            }
            internal virtual CSharpName QualificationNode {
                get { return null; }
            }
            internal virtual CSharpGreaterThanToken GreaterThanToken {
                get { return null; }
            }
            internal virtual IEnumerable<CSharpName> GenericArguments() {
                yield break;
            }
            internal virtual CSharpLessThanToken LessThanToken {
                get { return null; }
            }
        }
        private sealed class PredefinedTypeData : RootData {
            private CSharpKeywordToken m_keyword;

            internal PredefinedTypeData(CSharpName csharpName)
                : base(csharpName) {
            }

            private PredefinedTypeSyntax PredefinedTypeSyntax {
                get { return SyntaxNode as PredefinedTypeSyntax; }
            }

            internal override CSharpKeywordToken KeywordToken {
                get { return CSharpName.Get(ref m_keyword, PredefinedTypeSyntax.Keyword); }
            }
        }

        private abstract class ElementTypeData : RootData {
            private CSharpName m_undecoratedName;

            internal ElementTypeData(CSharpName csharpName)
                : base(csharpName) {
            }

            internal override CSharpName UndecoratedNode {
                get {
                    if (m_undecoratedName == null) {
                        m_undecoratedName = CSharpName;
                        while (m_undecoratedName.ElementTypeNode != null)
                            m_undecoratedName = m_undecoratedName.ElementTypeNode;
                    }
                    return m_undecoratedName;
                }
            }
            internal override CSharpIdentifierToken IdentifierToken {
                get { return UndecoratedNode.IdentifierToken; }
            }
            internal override CSharpKeywordToken KeywordToken {
                get { return UndecoratedNode.KeywordToken; }
            }
            internal override CSharpName QualificationNode {
                get { return UndecoratedNode.QualificationNode; }
            }
            internal override CSharpDotToken DotToken {
                get { return UndecoratedNode.DotToken; }
            }
            internal override CSharpColonColonToken ColonColonToken {
                get { return UndecoratedNode.ColonColonToken; }
            }
            internal override CSharpIdentifierToken AliasIdentifierToken {
                get { return UndecoratedNode.AliasIdentifierToken; }
            }
        }
        private sealed class NullableTypeData : ElementTypeData {
            private CSharpName m_elementType;
            private CSharpQuestionToken m_questionToken;

            internal NullableTypeData(CSharpName csharpName)
                : base(csharpName) {
            }

            private NullableTypeSyntax NullableTypeSyntax {
                get { return SyntaxNode as NullableTypeSyntax; }
            }

            internal override CSharpName ElementTypeNode {
                get { return CSharpName.Get(ref m_elementType, NullableTypeSyntax.ElementType); }
            }
            internal override CSharpQuestionToken QuestionToken {
                get { return CSharpName.Get(ref m_questionToken, NullableTypeSyntax.QuestionToken); }
            }
        }
        private sealed class PointerTypeData : ElementTypeData {
            private CSharpName m_elementType;
            private CSharpAsteriskToken m_asteriskToken;

            internal PointerTypeData(CSharpName csharpName)
                : base(csharpName) {
            }

            private PointerTypeSyntax PointerTypeSyntax {
                get { return SyntaxNode as PointerTypeSyntax; }
            }

            internal override CSharpName ElementTypeNode {
                get { return CSharpName.Get(ref m_elementType, PointerTypeSyntax.ElementType); }
            }
            internal override CSharpAsteriskToken AsteriskToken {
                get { return CSharpName.Get(ref m_asteriskToken, PointerTypeSyntax.AsteriskToken); }
            }
        }
        private sealed class ArrayTypeData : ElementTypeData {
            private CSharpName m_elementType;
            private IEnumerable<CSharpArrayRankSpecifierSyntax> m_rankSpecifiers;

            internal ArrayTypeData(CSharpName csharpName)
                : base(csharpName) {
            }

            private ArrayTypeSyntax ArrayTypeSyntax {
                get { return SyntaxNode as ArrayTypeSyntax; }
            }

            internal override CSharpName ElementTypeNode {
                get { return CSharpName.Get(ref m_elementType, ArrayTypeSyntax.ElementType); }
            }
            internal override IEnumerable<CSharpArrayRankSpecifierSyntax> RankSpecifierNodes() {
                return CSharpName.Get(ref m_rankSpecifiers, ArrayTypeSyntax.RankSpecifiers);
            }
        }

        private abstract class NameData : RootData {

            internal NameData(CSharpName csharpName)
                : base(csharpName) {
            }

            private NameSyntax NameSyntax {
                get { return SyntaxNode as NameSyntax; }
            }
        }

        private abstract class SimpleQualifiedName : NameData {
            protected CSharpName m_right;

            internal SimpleQualifiedName(CSharpName csharpName)
                : base(csharpName) {
            }

            protected abstract CSharpName Right { get; }

            internal override CSharpIdentifierToken IdentifierToken {
                get { return Right.IdentifierToken; }
            }
            internal override CSharpGreaterThanToken GreaterThanToken {
                get { return Right.GreaterThanToken; }
            }
            internal override IEnumerable<CSharpName> GenericArguments() {
                return Right.GenericArguments();
            }
            internal override CSharpLessThanToken LessThanToken {
                get { return Right.LessThanToken; }
            }
        }
        private sealed class AliasQualifiedNameData : SimpleQualifiedName {
            private CSharpIdentifierToken m_aliasIdentifierToken;
            private CSharpColonColonToken m_colonColonToken;

            internal AliasQualifiedNameData(CSharpName csharpName)
                : base(csharpName) {
            }

            private AliasQualifiedNameSyntax AliasQualifiedNameSyntax {
                get { return SyntaxNode as AliasQualifiedNameSyntax; }
            }

            protected override CSharpName Right {
                get { return CSharpName.Get(ref m_right, AliasQualifiedNameSyntax.Name); }
            }

            internal override CSharpIdentifierToken AliasIdentifierToken {
                get { return CSharpName.Get(ref m_aliasIdentifierToken, AliasQualifiedNameSyntax.Alias.Identifier); }
            }
            internal override CSharpColonColonToken ColonColonToken {
                get { return CSharpName.Get(ref m_colonColonToken, AliasQualifiedNameSyntax.ColonColonToken); }
            }
        }
        private sealed class QualifiedNameData : SimpleQualifiedName {
            private CSharpName m_qualification;
            private CSharpDotToken m_dot;
            private CSharpName m_alias;

            internal QualifiedNameData(CSharpName csharpName)
                : base(csharpName) {
            }

            private QualifiedNameSyntax QualifiedNameSyntax {
                get { return SyntaxNode as QualifiedNameSyntax; }
            }

            protected override CSharpName Right {
                get { return CSharpName.Get(ref m_right, QualifiedNameSyntax.Right); }
            }

            internal CSharpName Alias {
                get {
                    if (m_alias == null) {
                        m_alias = CSharpName;
                        while (m_alias.QualificationNode != null)
                            m_alias = m_alias.QualificationNode;
                    }
                    return m_alias;
                }
            }
            internal override CSharpName QualificationNode {
                get { return CSharpName.Get(ref m_qualification, QualifiedNameSyntax.Left); }
            }
            internal override CSharpDotToken DotToken {
                get { return CSharpName.Get(ref m_dot, QualifiedNameSyntax.DotToken); }
            }
            internal override CSharpIdentifierToken AliasIdentifierToken {
                get {
                    if (Alias == null)
                        return null;
                    return m_alias.AliasIdentifierToken; 
                }
            }
            internal override CSharpColonColonToken ColonColonToken {
                get { 
                    if (Alias == null)
                        return null;
                    return m_alias.ColonColonToken; 
                }
            }
        }

        private abstract class SimpleNameData : NameData {
            public CSharpIdentifierToken m_identifierToken;

            internal SimpleNameData(CSharpName csharpName)
                : base(csharpName) {
            }

            private SimpleNameSyntax SimpleNameSyntax {
                get { return SyntaxNode as SimpleNameSyntax; }
            }

            internal override CSharpIdentifierToken IdentifierToken {
                get { return CSharpName.Get(ref m_identifierToken, SimpleNameSyntax.Identifier); }
            }
        }
        private sealed class GenericNameData : SimpleNameData {
            private CSharpGreaterThanToken m_greaterThanToken;
            private IEnumerable<CSharpName> m_arguments;
            private CSharpLessThanToken m_lessThanToken;

            internal GenericNameData(CSharpName csharpName)
                : base(csharpName) {
            }

            private GenericNameSyntax GenericNameSyntax {
                get { return SyntaxNode as GenericNameSyntax; }
            }

            internal override CSharpGreaterThanToken GreaterThanToken {
                get { return CSharpName.Get(ref m_greaterThanToken, GenericNameSyntax.TypeArgumentList.GreaterThanToken); }
            }
            internal override IEnumerable<CSharpName> GenericArguments() {
                return CSharpName.Get(ref m_arguments, GenericNameSyntax.TypeArgumentList.Arguments);
            }
            internal override CSharpLessThanToken LessThanToken {
                get { return CSharpName.Get(ref m_lessThanToken, GenericNameSyntax.TypeArgumentList.LessThanToken); }
            }
        }
        private sealed class IdentifierNameData : SimpleNameData {

            internal IdentifierNameData(CSharpName csharpName)
                : base(csharpName) {
            }

            private IdentifierNameSyntax IdentifierNameSyntax {
                get { return SyntaxNode as IdentifierNameSyntax; }
            }
        }
        #endregion

        private RootData m_data;

        public CSharpName() { }
        internal CSharpName(SyntaxNode node, CSharpObject parent, CSharpSemanticModel semanticModel)
            : base(node, parent, semanticModel) {
        }

        private RootData Data {
            get {
                if (m_data == null)
                    m_data = RootData.Activate(this);
                return m_data;
            }
        }

        internal override SyntaxNodeOrToken Parse(string text) {
            return Syntax.ParseTypeName(text);
        }
        internal override IEnumerable Children() {
            if (HasElementTypeNode) {
                yield return ElementTypeNode;

                yield return AsteriskToken;
                yield return QuestionToken;
                yield return RankSpecifierNodes();
            } 

            else {

                if (HasQualificationNode) {
                    yield return QualificationNode;
                    yield return DotToken;
                }
                
                else {
                    yield return AliasIdentifierToken;
                    yield return ColonColonToken;
                }

                yield return KeywordToken;
                yield return IdentifierToken;

                yield return LessThanToken;
                yield return GenericArguments();
                yield return GreaterThanToken;
            }
        }

        private TypeSyntax TypeSyntax {
            get { return (TypeSyntax)SyntaxNode; }
        }

        #region Public Members
        public string Name {
            get { return TypeSyntax.ToString(); }
        }

        public bool IsPointer {
            get { return Data is PointerTypeData; }
        }
        public bool IsArray {
            get { return Data is ArrayTypeData; }
        }
        public bool IsNullable {
            get { return Data is NullableTypeData; }
        }

        public CSharpIdentifierToken AliasIdentifierToken {
            get { return Data.AliasIdentifierToken; }
        }
        public CSharpColonColonToken ColonColonToken {
            get { return Data.ColonColonToken; }
        }

        public bool HasQualificationNode {
            get { return QualificationNode != null; }
        }
        public CSharpName QualificationNode {
            get { return Data.QualificationNode; }
        }
        public CSharpDotToken DotToken {
            get { return Data.DotToken; }
        }
        public CSharpKeywordToken KeywordToken {
            get { return Data.KeywordToken; }
        }
        public CSharpIdentifierToken IdentifierToken {
            get { return Data.IdentifierToken; }
        }

        public bool HasElementTypeNode {
            get { return ElementTypeNode != null; }
        }
        public CSharpName UndecoratedNode {
            get { return Data.UndecoratedNode; }
        }
        public CSharpName ElementTypeNode {
            get { return Data.ElementTypeNode; }
        }
        public CSharpAsteriskToken AsteriskToken {
            get { return Data.AsteriskToken; }
        }
        public CSharpQuestionToken QuestionToken {
            get { return Data.QuestionToken; }
        }
        public IEnumerable<CSharpArrayRankSpecifierSyntax> RankSpecifierNodes() {
            return Data.RankSpecifierNodes();
        }

        public CSharpLessThanToken LessThanToken {
            get { return Data.LessThanToken; }
        }
        public IEnumerable<CSharpName> GenericArguments() {
            return Data.GenericArguments();
        }
        public CSharpGreaterThanToken GreaterThanToken {
            get { return Data.GreaterThanToken; }
        }
        #endregion
    }

    [CSharpSymbol(SyntaxKind.ArrayRankSpecifier)]
    public sealed class CSharpArrayRankSpecifierSyntax : CSharpNodeSyntax {

        internal CSharpArrayRankSpecifierSyntax(SyntaxNode node, CSharpObject parent, CSharpSemanticModel semanticModel)
            : base(node, parent, semanticModel) {
        }
    }

    [Declaration]
    public sealed class CSharpExpressionSyntax : CSharpNodeSyntax {

        internal override SyntaxNodeOrToken Reduce(SyntaxBinder binder) {
            return binder.GetExpression();
        }
        internal override SyntaxNodeOrToken Parse(string text) {
            return Syntax.ParseExpression(text);
        }
    }

    // helpers
    [Declaration]
    internal sealed class Block : Declaration {

        private bool m_openBraceOnNewLine;
        private bool m_inline;

        public Block(
            bool openBraceOnNewLine = false,
            bool inline = false) {

            m_openBraceOnNewLine = openBraceOnNewLine;
            m_inline = inline;
        }

        protected override IEnumerable Children(DeclarationContext context) {

            var isSubstantial = Declaration.IsSubstantial(Children());
            var content = new TextSingleSpaced() { Children() };
            var inline = !isSubstantial || (m_inline && !context.ContainsNewLine(content));

            if (inline) {
                yield return CSharpPunctuationToken.OpenBrace;
                yield return ' ';

                if (isSubstantial) {
                    yield return Children();
                    yield return ' ';
                }

                yield return CSharpPunctuationToken.CloseBrace;
            } else {
                if (m_openBraceOnNewLine)
                    yield return Environment.NewLine;

                yield return CSharpPunctuationToken.OpenBrace;
                yield return Environment.NewLine;

                if (isSubstantial) {
                    yield return new TextIndent() { 
                        content 
                    };
                    yield return Environment.NewLine;
                }

                yield return CSharpPunctuationToken.CloseBrace;
            }
        }
    }
    [Declaration]
    internal class Definition : Declaration {

        #region Namesapces/CompilationUnits
        internal object m_externs;
        internal object m_usings;
        #endregion

        #region Definition Union
        // attributes
        internal object m_attributes;

        // return type, field type, namespace name
        internal object m_typeName;

        // name
        internal object m_identifier;

        // parameters
        internal object m_parameters;

        // field\enum initializers
        internal object m_initializer;

        // type and method type parameters
        internal object m_typeParameters;

        // base type
        internal object m_baseTypesAndInterfaces;
        internal object m_constraints;

        // constructor chaining
        internal object m_baseCall;
        internal object m_thisCall;

        // hasBlock
        internal bool m_hasBlock;
        internal bool m_hasSemicolon;
        #endregion

        #region Modifiers
        internal bool m_isCompilationUnit;
        internal bool m_isNamespace;

        internal bool m_isStruct;
        internal bool m_isInterface;
        internal bool m_isEnum;
        internal bool m_isDelegate;
        internal bool m_isClass;

        internal bool m_isPublic;
        internal bool m_isInternal;
        internal bool m_isProtected;
        internal bool m_isPrivate;

        internal bool m_isStatic;
        internal bool m_isConst;
        internal bool m_isReadOnly;
        internal bool m_isSealed;

        internal bool m_isNew;
        internal bool m_isAbstract;
        internal bool m_isVirtual;
        internal bool m_isOverride;

        internal bool m_isPartial;
        internal bool m_isExtern;
        #endregion

        #region Constraints
        internal bool m_hasClassConstraint;
        internal bool m_hasStructConstraint;
        internal bool m_hasNewConstraint;
        internal bool m_hasOutConstraint;
        internal bool m_hasInConstraint;
        #endregion

        #region Private Members
        private IEnumerable Body(DeclarationContext frame) {
            if (m_hasSemicolon)
                return CSharpPunctuationToken.Semicolon;

            if (m_hasBlock) {
                return new Block { 
                    new TextDoubleSpaced {
                        m_isNamespace ? new TextJoin { ExternStatements(frame) } : null,
                        m_isNamespace ? new TextJoin { UsingStatements(frame) } : null,
                        new TextSingleSpaced {
                            base.Children() 
                        }
                    },
                };
            }

            // generic type parameters have neither a block nor semi-colon
            Contract.Assert(base.Children() == null);
            return null;
        }
        private IEnumerable Parameters() {
            if (m_parameters == null)
                return null;

            return new TextJoin(
                delimiter: new object[] { CSharpPunctuationToken.Comma, ' ' },
                prefix: CSharpPunctuationToken.OpenParen,
                suffix: CSharpPunctuationToken.CloseParen,
                force: true) {

                m_parameters
            };
        }
        private IEnumerable BaseTypesAndInterfaces(DeclarationContext frame) {

            return new TextJoin(
                delimiter: new object[] { CSharpPunctuationToken.Comma, ' ' },
                prefix: new object[] { CSharpPunctuationToken.Colon, ' ' }) { 

                frame.Flatten(m_baseTypesAndInterfaces, o => new CSharpName { o }),
            };
        }
        private IEnumerable TypeParameters(DeclarationContext frame, 
            out IEnumerable<CSharpTypeParameterSyntax> typeParameters) {
            
            typeParameters = frame.Flatten(
                m_typeParameters, o => new CSharpTypeParameterSyntax(o)).ToList();

            // type parameters (e.g. <T,U, ... ,V>)
            return new TextJoin(
                delimiter: new object[] { CSharpPunctuationToken.Comma, ' ' },
                prefix: CSharpPunctuationToken.LessThan,
                suffix: CSharpPunctuationToken.GreaterThan) {

                typeParameters
            };
        }
        private IEnumerable<CSharpAttributeGroupSyntax> AttributeGroups(DeclarationContext frame) {
            return frame.Flatten(m_attributes, o => new CSharpAttributeGroupSyntax { o });
        }
        private IEnumerable Modifiers() {
            if (m_isNamespace) yield return CSharpKeywordToken.Namespace;

            if (m_isPublic) yield return CSharpKeywordToken.Public;
            if (m_isPrivate) yield return CSharpKeywordToken.Private;
            if (m_isProtected) yield return CSharpKeywordToken.Protected;
            if (m_isInternal) yield return CSharpKeywordToken.Internal;

            if (m_isStatic) yield return CSharpKeywordToken.Static;
            if (m_isSealed) yield return CSharpKeywordToken.Sealed;
            if (m_isConst) yield return CSharpKeywordToken.Const;
            if (m_isReadOnly) yield return CSharpKeywordToken.ReadOnly;

            if (m_isNew) yield return CSharpKeywordToken.New;
            if (m_isAbstract) yield return CSharpKeywordToken.Abstract;
            if (m_isVirtual) yield return CSharpKeywordToken.Virtual;
            if (m_isOverride) yield return CSharpKeywordToken.Override;

            if (m_isExtern) yield return CSharpKeywordToken.Extern;
            if (m_isPartial) yield return CSharpKeywordToken.Partial;

            if (m_isStruct) yield return CSharpKeywordToken.Struct;
            if (m_isInterface) yield return CSharpKeywordToken.Interface;
            if (m_isEnum) yield return CSharpKeywordToken.Enum;
            if (m_isDelegate) yield return CSharpKeywordToken.Delegate;
            if (m_isClass) yield return CSharpKeywordToken.Class;

            if (m_hasInConstraint) yield return CSharpKeywordToken.In;
            if (m_hasOutConstraint) yield return CSharpKeywordToken.Out;
        }
        private IEnumerable Constraints(DeclarationContext frame) {

            return new TextJoin(
                delimiter: new object[] { CSharpPunctuationToken.Comma, ' ' },
                prefix: new TextJoin(' ', suffix: ' ') {
                    CSharpKeywordToken.Where, new CSharpIdentifierToken { m_identifier }, CSharpPunctuationToken.Colon
                }) {

                // class/struct constraint
                m_hasClassConstraint ? CSharpKeywordToken.Class : null,
                m_hasStructConstraint ? CSharpKeywordToken.Struct : null,

                // type constraints
                frame.Flatten(m_constraints, o => new CSharpName { o }), 

                // new() constraint
                m_hasNewConstraint ? new TextJoin {
                    CSharpKeywordToken.New, 
                    CSharpPunctuationToken.OpenParen, 
                    CSharpPunctuationToken.CloseParen,
                } : null,
            };
        }
        private IEnumerable<CSharpExternAliasSyntax> ExternStatements(DeclarationContext frame) {
            return frame.Flatten(m_externs, o => new CSharpExternAliasSyntax { o });
        }
        private IEnumerable<CSharpUsingSyntax> UsingStatements(DeclarationContext frame) {
            return frame.Flatten(m_usings, o => new CSharpUsingSyntax { o });
        }
        #endregion

        private IEnumerable CompilationUnitChildren(DeclarationContext frame) {
            return new TextDoubleSpaced {
                new TextSingleSpaced { ExternStatements(frame) },
                new TextSingleSpaced { UsingStatements(frame) },
                new TextSingleSpaced { AttributeGroups(frame) },
                new TextSingleSpaced { base.Children() }
            };
        }
        protected override IEnumerable Children(DeclarationContext frame) {
            if (m_isCompilationUnit)
                return CompilationUnitChildren(frame);

            var nl = Environment.NewLine;

            IEnumerable<CSharpTypeParameterSyntax> typeParameters;

            return new TextSingleSpaced {
                new TextJoin { AttributeGroups(frame) },

                new TextJoin(' ') {
                    new TextJoin {
                        new TextJoin(' ') { 
                            Modifiers(), 
                            frame.Flatten(m_typeName, o => new CSharpName { o }),
                            new CSharpIdentifierToken { m_identifier } 
                        },

                        TypeParameters(frame, out typeParameters),

                        Parameters(),

                        new TextIndent {
                            new TextSingleSpaced(Environment.NewLine) {

                                BaseTypesAndInterfaces(frame),

                                // constraints (e.g. where class, Foo, IBar)
                                typeParameters.Select(o => o.Builder.Constraints(frame))
                            },
                        },
                    },

                    Body(frame)
                },
            };
        }
    }

    // nodes
    public enum CSharpAttributeGroupTarget {
        None,
        Type,
        Parameter,
        Event,
        Field,
        Method,
        Property,
        ReturnParameter,
        Assembly,
        Module
    }
    [CSharpSymbol(SyntaxKind.AttributeList)]
    public sealed class CSharpAttributeGroupSyntax : CSharpNodeSyntax {

        private class Info : Declaration {
            internal CSharpAttributeGroupTarget m_type;

            protected override IEnumerable Substance() {
                return Children();
            }
            protected override IEnumerable Children(DeclarationContext frame) {

                object keyword = null;
                if (m_type == CSharpAttributeGroupTarget.Type) keyword = CSharpKeywordToken.Type;
                else if (m_type == CSharpAttributeGroupTarget.Assembly) keyword = CSharpKeywordToken.Assembly;
                else if (m_type == CSharpAttributeGroupTarget.Module) keyword = CSharpKeywordToken.Module;
                else if (m_type == CSharpAttributeGroupTarget.Parameter) keyword = CSharpKeywordToken.Params;
                else if (m_type == CSharpAttributeGroupTarget.ReturnParameter) keyword = CSharpKeywordToken.Return;
                else if (m_type == CSharpAttributeGroupTarget.Event) keyword = CSharpKeywordToken.Event;
                else if (m_type == CSharpAttributeGroupTarget.Field) keyword = CSharpKeywordToken.Field;
                else if (m_type == CSharpAttributeGroupTarget.Method) keyword = CSharpKeywordToken.Method;
                else if (m_type == CSharpAttributeGroupTarget.Property) keyword = CSharpKeywordToken.Property;

                return new object[] {
                    CSharpPunctuationToken.OpenBracket, 
                    new TextJoin(delimiter: new object[] { CSharpPunctuationToken.Comma, ' ' },
                        prefix: new TextJoin(
                            suffix: new object[] { CSharpPunctuationToken.Colon, ' ' }) { keyword }) {

                        frame.Flatten(Children(), o => new CSharpAttributeSyntax(o))
                    },
                    CSharpPunctuationToken.CloseBracket, 
                };
            }
        }

        private CSharpKeywordToken m_targetKeyword;
        private IEnumerable<CSharpAttributeSyntax> m_attributes;

        #region Constructor
        public CSharpAttributeGroupSyntax(
            CSharpAttributeGroupTarget type = CSharpAttributeGroupTarget.None,
            bool isType = false,
            bool isParameter = false,
            bool isReturnParameter = false,
            bool isEvent = false,
            bool isField = false,
            bool isMethod = false,
            bool isProperty = false,
            bool isAssembly = false,
            bool isModule = false)
            : base(new Info {
                m_type = isType ? CSharpAttributeGroupTarget.Type :
                    isParameter ? CSharpAttributeGroupTarget.Parameter :
                    isReturnParameter ? CSharpAttributeGroupTarget.ReturnParameter :
                    isEvent ? CSharpAttributeGroupTarget.Event :
                    isField ? CSharpAttributeGroupTarget.Field :
                    isMethod ? CSharpAttributeGroupTarget.Method :
                    isProperty ? CSharpAttributeGroupTarget.Property :
                    isAssembly ? CSharpAttributeGroupTarget.Assembly :
                    isModule ? CSharpAttributeGroupTarget.Module : 
                    CSharpAttributeGroupTarget.None
            }) {
        }
        #endregion
        internal CSharpAttributeGroupSyntax(SyntaxNode node, CSharpObject parent, CSharpSemanticModel semanticModel)
            : base(node, parent, semanticModel) {
        }

        private AttributeListSyntax AttributeGroup {
            get { return (AttributeListSyntax)SyntaxNode; }
        }

        internal override SyntaxNodeOrToken Reduce(SyntaxBinder binder) {
            return binder.TryGetAttributeGroup();
        }

        public CSharpKeywordToken TargetKeyword {
            get { return Get(ref m_targetKeyword, AttributeGroup.Target.Identifier); }
        }

        public CSharpAttributeGroupTarget Target {
            get {
                var keyword = TargetKeyword;
                if (keyword is CSharpTypeKeyword) return CSharpAttributeGroupTarget.Type;
                if (keyword is CSharpAssemblyKeyword) return CSharpAttributeGroupTarget.Assembly;
                if (keyword is CSharpModuleKeyword) return CSharpAttributeGroupTarget.Module;
                if (keyword is CSharpParamKeyword) return CSharpAttributeGroupTarget.Parameter;
                if (keyword is CSharpReturnKeyword) return CSharpAttributeGroupTarget.ReturnParameter;
                if (keyword is CSharpEventKeyword) return CSharpAttributeGroupTarget.Event;
                if (keyword is CSharpFieldKeyword) return CSharpAttributeGroupTarget.Field;
                if (keyword is CSharpMethodKeyword) return CSharpAttributeGroupTarget.Method;
                if (keyword is CSharpPropertyKeyword) return CSharpAttributeGroupTarget.Property;
                return CSharpAttributeGroupTarget.None;
            }
        }
        public IEnumerable<CSharpAttributeSyntax> Attributes() {
            return Get(ref m_attributes, AttributeGroup.Attributes);
        }
    }
    [CSharpSymbol(SyntaxKind.Attribute), Declaration]
    public sealed class CSharpAttributeSyntax : CSharpNodeSyntax {

        [Declaration]
        private class Info : Declaration {
            internal object m_name;

            protected override IEnumerable Children(DeclarationContext frame) {
                yield return frame.Flatten(m_name, o => new CSharpName { o });
                yield return new TextJoin(
                    delimiter: new object[] { CSharpPunctuationToken.Comma, ' ' },
                    prefix: CSharpPunctuationToken.OpenParen,
                    suffix: CSharpPunctuationToken.CloseParen) {

                    frame.Flatten(Children(), o => new CSharpAttributeArgumentSyntax { o })
                };
            }
        }

        public CSharpAttributeSyntax(object name) 
            : base(new Info {
                m_name = name
            }) {
        }
        internal CSharpAttributeSyntax(SyntaxNode node, CSharpObject parent, CSharpSemanticModel semanticModel)
            : base(node, parent, semanticModel) {
        }

        internal override SyntaxNodeOrToken Reduce(SyntaxBinder binder) {
            return binder.GetAttribute();
        }
    }
    [CSharpSymbol(SyntaxKind.AttributeArgument)]
    public sealed class CSharpAttributeArgumentSyntax : CSharpNodeSyntax {

        private class Info : Declaration {
            internal object m_name;
            internal bool m_equals;

            protected override IEnumerable Substance() {
                return Children();
            }
            protected override IEnumerable Children(DeclarationContext frame) {
                var prefixSuffix = m_equals ?
                    new object[] { ' ', CSharpPunctuationToken.Equals, ' ' } :
                    new object[] { CSharpPunctuationToken.Colon, ' ' };

                var name = new CSharpIdentifierToken { m_name };

                return new TextJoin(
                    prefix: new TextJoin(suffix: prefixSuffix) { name }) {

                    frame.Flatten(Children(), o => new CSharpExpressionSyntax { o })
                };
            }
        }

        public CSharpAttributeArgumentSyntax(object name = null, bool equals = false)
            : base(new Info {
                m_name = name,
                m_equals = equals,
            }) {
        }

        internal override SyntaxNodeOrToken Reduce(SyntaxBinder binder) {
            return binder.TryGetAttributeArgument();
        }
    }
    [CSharpSymbol(SyntaxKind.StringLiteralExpression)]
    public sealed class CSharpStringSyntax : CSharpNodeSyntax {

        private static readonly Dictionary<char, char> m_escapeCharacter;

        static CSharpStringSyntax() {
            m_escapeCharacter = new Dictionary<char, char>();
            var o = m_escapeCharacter;

            o['"'] = '"';
            o['\\'] = '\\';
            o['\a'] = 'a';
            o['\b'] = 'b';
            o['\f'] = 'f';
            o['\n'] = 'n';
            o['\r'] = 'r';
            o['\t'] = 't';
            o['\v'] = 'v';
        }

        [Declaration(SubstituteCharacters = new[] { 
            '"', '\\', '\a', '\b', '\f', '\n', '\r', '\t', '\v'
        })]
        internal class Escaper : TextDeclaration {

            protected override IEnumerable Substitute(DeclarationContext frame, char character) {
                var escapeCharacter = m_escapeCharacter[character];
                return new DeclarationContinueSubstitutionAfter(frame) {
                    '\\', escapeCharacter
                };
            }
        }

        [Declaration(SubstituteCharacters = new[] { 
            '"', '\\', '\a', '\b', '\f', '\n', '\r', '\t', '\v'
        })]
        internal class VerbatimEscaper : CSharpStringSyntax.Escaper {

            protected override IEnumerable Substitute(DeclarationContext frame, char character) {
                if (character == '"')
                    return new DeclarationContinueSubstitutionAfter(frame) { "\"\"" };

                return base.Substitute(frame, character);
            }
        }

        private bool m_verbatim;

        public CSharpStringSyntax(object value, bool verbatim = false)
            : base(value) {

            m_verbatim = verbatim;
        }
        public CSharpStringSyntax(bool verbatim = false)
            : this(null, verbatim) {
        }

        internal override SyntaxNodeOrToken Parse(string text) {
            string rawText = null;

            if (m_verbatim)
                rawText = new TextJoin { "@\"", new VerbatimEscaper { text }, "\""}.ReadToEnd();
            else 
                rawText = new TextJoin { "\"", new Escaper { text }, "\"" }.ReadToEnd();

            var literal = Syntax.Literal(rawText, text);
            Contract.Assert(literal.Kind == SyntaxKind.StringLiteralToken);

            return Syntax.LiteralExpression(SyntaxKind.StringLiteralExpression, literal);
        }
    }
    [CSharpSymbol(SyntaxKind.CharacterLiteralExpression)]
    public sealed class CSharpCharacterSyntax : CSharpNodeSyntax {

        [Declaration(SubstituteCharacters = new[] { 
            '\'', '\\', '\a', '\b', '\f', '\n', '\r', '\t', '\v'
        })]
        internal class Escaper : CSharpStringSyntax.Escaper {

            protected override IEnumerable Substitute(DeclarationContext frame, char character) {
                if (character == '\'')
                    return new DeclarationContinueSubstitutionAfter(frame) { "\\'" };

                return base.Substitute(frame, character);
            }
        }

        public CSharpCharacterSyntax() { }
        public CSharpCharacterSyntax(object value)
            : base(value) {
        }

        internal override SyntaxNodeOrToken Parse(string text) {
            var rawText = new TextJoin { "'", new Escaper { text }, "'" }.ReadToEnd();
            var literal = Syntax.Literal(rawText, text[0]);
            Contract.Assert(literal.Kind == SyntaxKind.CharacterLiteralToken);

            return Syntax.LiteralExpression(SyntaxKind.CharacterLiteralExpression, literal);
        }
    }

    // definitions
    [Declaration]
    public abstract class CSharpDefinitionSyntax : CSharpNodeSyntax {
        internal CSharpDefinitionSyntax(Definition definition)
            : base(definition) {
        }
        internal CSharpDefinitionSyntax(SyntaxNode node, CSharpObject parent, CSharpSemanticModel semanticModel)
            : base(node, parent, semanticModel) {
        }

        internal new Definition Builder {
            get { return (Definition)base.Builder; }
        }
    }
    public abstract class CSharpMemberSyntax : CSharpDefinitionSyntax {

        internal CSharpMemberSyntax(Definition definition)
            : base(definition) {
        }
        internal CSharpMemberSyntax(SyntaxNode node, CSharpObject parent, CSharpSemanticModel semanticModel)
            : base(node, parent, semanticModel) {
        }

        public virtual IEnumerable<CSharpAttributeGroupSyntax> AttributeGroups() {
            throw new NotImplementedException();
        }
        public virtual IEnumerable<CSharpAttributeSyntax> Attributes() {
            throw new NotImplementedException();
        }
    }
    [CSharpSymbol(
        SyntaxKind.ClassDeclaration, 
        SyntaxKind.InterfaceDeclaration, 
        SyntaxKind.StructDeclaration,
        SyntaxKind.EnumDeclaration)]
    public sealed class CSharpTypeSyntax : CSharpMemberSyntax {

        private CSharpIdentifierToken m_identifierToken;
        private IEnumerable<CSharpAttributeGroupSyntax> m_attributeGroups;

        #region Constructor
        public CSharpTypeSyntax(
            object identifier,
            object typeParameters = null,
            object attributes = null,
            bool isPublic = false, bool isInternal = false, bool isProtected = false, bool isPrivate = false,
            bool isStatic = false, bool isSealed = false, bool isNew = false, bool isAbstract = false,
            bool isPartial = false, bool isExtern = false,
            bool isStruct = false, bool isInterface = false, bool isEnum = false,
            object baseTypeAndInterfaces = null)

            : base(new Definition {
                    m_identifier = identifier,
                    m_typeParameters = typeParameters,
                    m_attributes = attributes,

                    m_isStruct = isStruct,
                    m_isInterface = isInterface,
                    m_isEnum = isEnum,
                    m_isClass = !(isStruct || isInterface || isEnum),

                    m_isPublic = isPublic,
                    m_isInternal = isInternal,
                    m_isProtected = isProtected,
                    m_isPrivate = isPrivate,

                    m_isStatic = isStatic,
                    m_isSealed = isSealed,
                    m_isNew = isNew,

                    m_isAbstract = isAbstract,

                    m_isPartial = isPartial,
                    m_isExtern = isExtern,

                    m_baseTypesAndInterfaces = baseTypeAndInterfaces,

                    m_hasBlock = !isExtern,
                    m_hasSemicolon = isExtern
                }
            ) { }
        internal CSharpTypeSyntax(SyntaxNode node, CSharpObject parent, CSharpSemanticModel semanticModel)
            : base(node, parent, semanticModel) {
        }
        #endregion

        private BaseTypeDeclarationSyntax BaseTypeDeclarationSyntax {
            get { return SyntaxNode as BaseTypeDeclarationSyntax; }
        }
        private TypeDeclarationSyntax TypeDeclarationSyntax {
            get { return SyntaxNode as TypeDeclarationSyntax; }
        }
        private ClassDeclarationSyntax ClassDeclarationSyntax {
            get { return SyntaxNode as ClassDeclarationSyntax; }
        }
        private StructDeclarationSyntax StructDeclarationSyntax {
            get { return SyntaxNode as StructDeclarationSyntax; }
        }
        private InterfaceDeclarationSyntax InterfaceDeclarationSyntax {
            get { return SyntaxNode as InterfaceDeclarationSyntax; }
        }
        private EnumDeclarationSyntax EnumDeclarationSyntax {
            get { return SyntaxNode as EnumDeclarationSyntax; }
        }

        public string Name {
            get { return TypeDeclarationSyntax.Identifier.ValueText; }
        }
        public CSharpIdentifierToken IdentifierToken {
            get { return Get(ref m_identifierToken, TypeDeclarationSyntax.Identifier); }
        }

        internal override SyntaxNodeOrToken Reduce(SyntaxBinder binder) {
            return binder.GetTypeDeclaration();
        }

        public override IEnumerable<CSharpAttributeGroupSyntax> AttributeGroups() {
            return Get(ref m_attributeGroups, BaseTypeDeclarationSyntax.AttributeLists);
        }
        public override IEnumerable<CSharpAttributeSyntax> Attributes() {
            return AttributeGroups().SelectMany(o => o.Attributes());
        }
    }
    [CSharpSymbol(SyntaxKind.Parameter)]
    public sealed class CSharpTypeParameterSyntax : CSharpMemberSyntax {

        private IEnumerable<CSharpAttributeGroupSyntax> m_attributeGroups;

        #region Constructor
        public CSharpTypeParameterSyntax(object name,
            object attributes = null,
            object constraints = null,
            bool hasClassConstraint = false,
            bool hasStructConstraint = false,
            bool hasNewConstraint = false,
            bool hasOutConstraint = false,
            bool hasInConstraint = false)
            : base(new Definition() {
                    m_identifier = name,
                    m_attributes = attributes,
                    m_constraints = constraints,

                    m_hasClassConstraint = hasClassConstraint,
                    m_hasStructConstraint = hasStructConstraint,
                    m_hasNewConstraint = hasNewConstraint,
                    m_hasOutConstraint = hasOutConstraint,
                    m_hasInConstraint = hasInConstraint,
                }
            ) { }
        #endregion

        private TypeParameterSyntax TypeParameterSyntax {
            get { return (TypeParameterSyntax)SyntaxNode; }
        }

        internal override SyntaxNodeOrToken Reduce(SyntaxBinder binder) {
            return binder.GetTypeParameter();
        }

        public override IEnumerable<CSharpAttributeGroupSyntax> AttributeGroups() {
            return Get(ref m_attributeGroups, TypeParameterSyntax.AttributeLists);
        }
        public override IEnumerable<CSharpAttributeSyntax> Attributes() {
            return AttributeGroups().SelectMany(o => o.Attributes());
        }
    }
    [CSharpSymbol(SyntaxKind.MethodDeclaration)]
    public sealed class CSharpMethodSyntax : CSharpMemberSyntax {

        private IEnumerable<CSharpAttributeGroupSyntax> m_attributeGroups;

        #region Constructor
        public CSharpMethodSyntax(
            object identifier,
            object typeParameters = null,
            object parameters = null,
            object returnType = null,
            object baseCall = null,
            object thisCall = null,
            object attributes = null,
            bool isPublic = false, bool isInternal = false, bool isProtected = false, bool isPrivate = false,
            bool isStatic = false, bool isSealed = false, bool isNew = false,
            bool isAbstract = false, bool isVirtual = false, bool isOverride = false,
            bool isPartial = false, bool isExtern = false)

            : base(new Definition {
                    m_attributes = attributes,

                    m_isPublic = isPublic,
                    m_isInternal = isInternal,
                    m_isProtected = isProtected,
                    m_isPrivate = isPrivate,

                    m_isStatic = isStatic,
                    m_isSealed = isSealed,
                    m_isNew = isNew,

                    m_isAbstract = isAbstract,
                    m_isVirtual = isVirtual,
                    m_isOverride = isOverride,

                    m_isPartial = isPartial,
                    m_isExtern = isExtern,

                    m_typeName = returnType ?? typeof(void),
                    m_identifier = identifier,
                    m_typeParameters = typeParameters,
                    m_parameters = parameters ?? new object[] { },
                    m_baseCall = baseCall,
                    m_thisCall = thisCall,

                    m_hasBlock = !isAbstract && !isPartial && !isExtern,
                    m_hasSemicolon = isAbstract || isPartial || isExtern
                }
            ) { }
        #endregion

        internal override SyntaxNodeOrToken Reduce(SyntaxBinder binder) {
            return binder.GetMethodDeclaration();
        }

        private BaseMethodDeclarationSyntax BaseMethodDeclarationSyntax {
            get { return (BaseMethodDeclarationSyntax)SyntaxNode; }
        }

        public override IEnumerable<CSharpAttributeGroupSyntax> AttributeGroups() {
            return Get(ref m_attributeGroups, BaseMethodDeclarationSyntax.AttributeLists);
        }
        public override IEnumerable<CSharpAttributeSyntax> Attributes() {
            return AttributeGroups().SelectMany(o => o.Attributes());
        }
    }

    // namespaces
    [CSharpSymbol(SyntaxKind.UsingDirective)]
    public sealed class CSharpUsingSyntax : CSharpNodeSyntax {

        private class Info : Declaration {
            internal object Alias;

            protected override IEnumerable Children(DeclarationContext frame) {

                return new TextJoin(' ', suffix: CSharpPunctuationToken.Semicolon) {
                    CSharpKeywordToken.Using,

                    Alias != null ? new TextJoin(' ', 
                        suffix: new object[] { ' ', CSharpPunctuationToken.Equals }) {

                        new CSharpIdentifierToken { Alias }
                    } : null,

                    frame.Flatten(Children(), o => new CSharpName { o })
                };
            }
        }

        private CSharpUsingKeyword m_usingKeyword;
        private CSharpIdentifierToken m_aliasIdentifierToken;
        private CSharpEqualsToken m_equalsToken;
        private CSharpName m_name;
        private CSharpSemicolonToken m_semicolonToken;

        public CSharpUsingSyntax(object alias = null)
            : base(new Info {
                Alias = alias
            }) {
        }
        internal CSharpUsingSyntax(SyntaxNode node, CSharpObject parent, CSharpSemanticModel semanticModel)
            : base(node, parent, semanticModel) {
        }

        internal UsingDirectiveSyntax UsingDirectiveSyntax {
            get { return (UsingDirectiveSyntax)SyntaxNode; }
        }
        internal override IEnumerable Children() {
            yield return UsingKeyword;
            yield return AliasIdentifierToken;
            yield return EqualsToken;
            yield return NameNode;
            yield return SemicolonToken;
        }

        public string Name {
            get { return NameNode.Name; }
        }
        public string Alias {
            get { return UsingDirectiveSyntax.Alias.Name.Identifier.ValueText; }
        }
        public CSharpTypeSyntax AliasSymbol {
            get { return SemanticModel.GetDeclarationType(UsingDirectiveSyntax); }
        }

        public CSharpToken UsingKeyword {
            get { return Get(ref m_usingKeyword, UsingDirectiveSyntax.UsingKeyword); }
        }
        public CSharpToken AliasIdentifierToken {
            get { 
                var alias = UsingDirectiveSyntax.Alias;
                if (alias == null)
                    return null;
                return Get(ref m_aliasIdentifierToken, alias.Name.Identifier); 
            }
        }
        public CSharpToken EqualsToken {
            get {
                var alias = UsingDirectiveSyntax.Alias;
                if (alias == null)
                    return null;
                return Get(ref m_equalsToken, alias.EqualsToken); 
            }
        }
        public CSharpName NameNode {
            get { return Get(ref m_name, UsingDirectiveSyntax.Name); }
        }
        public CSharpToken SemicolonToken {
            get { return Get(ref m_semicolonToken, UsingDirectiveSyntax.SemicolonToken); }
        }

        internal override SyntaxNodeOrToken Reduce(SyntaxBinder binder) {
            return binder.GetUsingDeclaration();
        }
    }
    [CSharpSymbol(SyntaxKind.ExternAliasDirective)]
    public sealed class CSharpExternAliasSyntax : CSharpNodeSyntax {

        private class Info : Declaration {
            internal object Alias;

            protected override IEnumerable Children(DeclarationContext frame) {

                return new TextJoin(' ', suffix: CSharpPunctuationToken.Semicolon) {
                    CSharpKeywordToken.Extern,
                    CSharpKeywordToken.Alias,
                    new CSharpIdentifierToken { Children() }
                };
            }
        }

        public CSharpExternAliasSyntax()
            : base(new Info()) {
        }
        internal CSharpExternAliasSyntax(ExternAliasDirectiveSyntax node)
            : base(node) {
        }

        internal override SyntaxNodeOrToken Reduce(SyntaxBinder binder) {
            return binder.GetExternAliasDeclaration();
        }
    }

    [CSharpSymbol(SyntaxKind.NamespaceDeclaration), Declaration]
    public sealed class CSharpNamespaceSyntax : CSharpNodeSyntax {

        private CSharpNamespaceKeyword m_namespaceKeyword;
        private CSharpName m_name;
        private CSharpOpenBraceToken m_openBraceToken;
        private CSharpCloseBraceToken m_closeBraceToken;
        private CSharpSemicolonToken m_semicolonToken;

        public CSharpNamespaceSyntax(
            object name,
            object externs = null,
            object usings = null)
            : base(new Definition {
                m_typeName = name,
                m_externs = externs,
                m_usings = usings,
                m_isNamespace = true,
                m_hasBlock = true
            }) {
        }
        internal CSharpNamespaceSyntax(SyntaxNode node, CSharpObject parent, CSharpSemanticModel semanticModel)
            : base(node, parent, semanticModel) {
        }

        internal NamespaceDeclarationSyntax NamespaceDeclarationSyntax {
            get { return (NamespaceDeclarationSyntax)SyntaxNode; }
        }
        internal override IEnumerable Children() {
            yield return NamespaceKeyword;
            yield return NameNode;
            yield return OpenBraceToken;
            //yield return Members();
            yield return CloseBraceToken;
            yield return m_semicolonToken;
        }

        public IEnumerable<CSharpNodeSyntax> Members() {
            throw new NotImplementedException();
        }
        public CSharpNamespaceKeyword NamespaceKeyword {
            get { return Get(ref m_namespaceKeyword, NamespaceDeclarationSyntax.NamespaceKeyword); }
        }
        public CSharpName NameNode {
            get { return Get(ref m_name, NamespaceDeclarationSyntax.Name); }
        }
        public CSharpOpenBraceToken OpenBraceToken {
            get { return Get(ref m_openBraceToken, NamespaceDeclarationSyntax.OpenBraceToken); }
        }
        public CSharpCloseBraceToken CloseBraceToken {
            get { return Get(ref m_closeBraceToken, NamespaceDeclarationSyntax.CloseBraceToken); }
        }
        public CSharpSemicolonToken SemicolonToken {
            get { return Get(ref m_semicolonToken, NamespaceDeclarationSyntax.SemicolonToken); }
        }

        public IEnumerable<UsingDirectiveSyntax> Usings() {
            return Members().OfType<UsingDirectiveSyntax>();
        }
        public IEnumerable<CSharpNamespaceSyntax> Namespaces() {
            return Members().OfType<CSharpNamespaceSyntax>();
        }
        public IEnumerable<CSharpTypeSyntax> Types() {
            return Members().OfType<CSharpTypeSyntax>();
        }

        internal override SyntaxNodeOrToken Reduce(SyntaxBinder binder) {
            return binder.GetNamespaceDeclaration();
        }
    }

    [CSharpSymbol(SyntaxKind.CompilationUnit), Declaration]
    public sealed class CSharpCompilationUnitSyntax : CSharpNodeSyntax {

        private string m_file;
        private SyntaxTree m_tree;
        private CSharpCompilation m_compilation;

        // children
        private IEnumerable<CSharpExternAliasSyntax> m_externs;
        private IEnumerable<CSharpUsingSyntax> m_usings;
        private IEnumerable<CSharpAttributeGroupSyntax> m_attributes;
        private IEnumerable<CSharpNodeSyntax> m_members;
        private CSharpEndOfFlieToken m_endOfFileToken;

        public CSharpCompilationUnitSyntax()
            : base(new Definition { m_isCompilationUnit = true }) { }
        public CSharpCompilationUnitSyntax(
            object externs = null,
            object usings = null,
            object attributes = null)
            : base(new Definition {
                m_externs = externs,
                m_usings = usings,
                m_attributes = attributes,
                m_isCompilationUnit = true,
                m_hasBlock = false,
            }) {
        }

        internal CSharpCompilationUnitSyntax(
            SyntaxTree tree, 
            CSharpCompilation compilation)
        : base(
            node: tree.GetRoot(), 
            parent: null, 
            semanticModel: null// new CSharpSemanticModel(compilation.GetSemanticModel(tree), compilation)
        ) {
            m_tree = tree;
            m_compilation = compilation;
        }
        internal CSharpCompilationUnitSyntax(CompilationUnitSyntax compilationUnitSyntax)
            : base(node: compilationUnitSyntax, parent: null, semanticModel: null) {
        }

        private SyntaxNodeOrToken RebindTriviaAfterTransform(SyntaxNodeOrToken original, SyntaxNodeOrToken transform) {
            if (!transform.GetLeadingTrivia().Any())
                transform = transform.WithLeadingTrivia(original.GetLeadingTrivia());

            if (!transform.GetTrailingTrivia().Any())
                transform = transform.WithTrailingTrivia(original.GetTrailingTrivia());

            return transform;
        }

        internal SyntaxTree Tree {
            get {
                if (m_tree == null)
                    m_tree = SyntaxTree.Create(CompilationUnitSyntax, m_file);
                return m_tree;
            }
        }
        internal CompilationUnitSyntax CompilationUnitSyntax {
            get { return (CompilationUnitSyntax)base.SyntaxNode; }
        }
        internal override IEnumerable Children() {
            yield return ExternAliases();
            yield return Usings();
            yield return AttributeGroups();
            yield return Members();
            yield return EndOfFileToken;
        }

        internal override SyntaxNodeOrToken Reduce(SyntaxBinder binder) {
            return binder.GetCompilationUnit();
        }
        internal override SyntaxNodeOrToken Parse(string text) {
            return Syntax.ParseCompilationUnit(text);
        }
        protected override IEnumerable NodesAndTokens(DeclarationContext frame) {
            yield return ExternAliases();
            yield return Usings();
            yield return AttributeGroups();
            yield return Members();
        }

        public CSharpCompilationUnitSyntax Transform(
            IEnumerable<CSharpObject> targets,
            Func<CSharpObject, CSharpObject> transform) {

            // fetch all targets
            targets = targets.ToList();

            // replace nodes
            var result = CompilationUnitSyntax.ReplaceNodes(
                targets.OfType<CSharpNodeSyntax>().Select(o => o.SyntaxNode),
                (x, o) => RebindTriviaAfterTransform(o, transform(Activate(o)).SyntaxNode).AsNode());

            // replace tokens
            result = result.ReplaceTokens(
                targets.OfType<CSharpToken>().Select(o => o.SyntaxToken),
                (x, o) => RebindTriviaAfterTransform(o, transform(Activate(o)).SyntaxToken).AsToken());

            // replace trivia
            result = result.ReplaceTrivia(
                targets.OfType<CSharpTrivia>().Select(o => o.SyntaxTrivia),
                (x, o) => transform(Activate(o)).SyntaxTrivia);

            // activate new compilation unit
            return new CSharpCompilationUnitSyntax(result) {
                m_file = m_file
            };
        }

        public CSharpEndOfFlieToken EndOfFileToken {
            get { return Get(ref m_endOfFileToken, CompilationUnitSyntax.EndOfFileToken); }
        }

        public IEnumerable<CSharpAttributeGroupSyntax> AttributeGroups() {
            return Get(ref m_attributes, CompilationUnitSyntax.AttributeLists);
        }
        public IEnumerable<CSharpAttributeSyntax> Attributes() {
            return AttributeGroups().SelectMany(o => o.Attributes());
        }

        public IEnumerable<CSharpExternAliasSyntax> ExternAliases() {
            return Get(ref m_externs, CompilationUnitSyntax.Externs);
        }
        public IEnumerable<CSharpUsingSyntax> Usings() {
            return Get(ref m_usings, CompilationUnitSyntax.Usings);
        }

        public IEnumerable<CSharpNodeSyntax> Members() {
            return Get(ref m_members, CompilationUnitSyntax.Members);
        }
        public IEnumerable<CSharpNamespaceSyntax> Namespaces() {
            return Members().OfType<CSharpNamespaceSyntax>();
        }
        public IEnumerable<CSharpTypeSyntax> Types() {
            return Members().OfType<CSharpTypeSyntax>();
        }

        public string File {
            get { return m_file; }
        }
    }
}
